# zargs Implementation Plan ## Project Structure ``` lib/zargs/ ├── src/ │ ├── main.zig # Public API exports │ ├── ArgumentRegistry.zig # Core registry implementation │ ├── ArgumentType.zig # Type system and conversions │ ├── parsing.zig # Argv parsing logic │ ├── help.zig # Help text generation │ └── metadata.zig # Metadata extraction from structs ├── tests/ │ ├── basic_test.zig # Basic functionality │ ├── collision_test.zig # Type collision detection │ ├── parsing_test.zig # Argument parsing │ └── help_test.zig # Help generation ├── examples/ │ ├── simple.zig # Minimal example │ ├── game_engine.zig # Multi-module game engine example │ └── persistence.zig # Help text persistence example ├── research/ # Design documents (existing) ├── todo/ # Implementation tracking (current) └── build.zig # Build configuration ``` ## Phase 1: Core Type System (Week 1) ### 1.1 ArgumentType Implementation **File:** `src/ArgumentType.zig` **Tasks:** - [ ] Define `ArgumentType` enum with all supported types - [ ] `bool`, `u8`, `u16`, `u32`, `u64` - [ ] `i8`, `i16`, `i32`, `i64` - [ ] `string` ([]const u8) - [ ] `string_list` ([]const []const u8) - [ ] `enum_type` (for Zig enums) - [ ] Implement `fromZigType(comptime T: type)` function - [ ] Handle `bool` - [ ] Handle integers with proper signedness/width detection - [ ] Handle string slices - [ ] Handle string list slices - [ ] Handle enums - [ ] Handle `?T` (optional) by unwrapping - [ ] Provide clear compile errors for unsupported types - [ ] Implement `matches(self, other)` for type compatibility - [ ] Add unit tests for type detection **Acceptance Criteria:** - All Zig primitive types correctly map to ArgumentType - Optional types unwrap correctly - Clear compile errors for unsupported types (structs, unions, etc.) - Type compatibility checker works correctly **Estimated Time:** 1-2 days --- ### 1.2 ParsedValue Union **File:** `src/ArgumentType.zig` (same file) **Tasks:** - [ ] Define `ParsedValue` tagged union - [ ] Implement conversion functions: - [ ] `fromString(arg_type: ArgumentType, s: []const u8, allocator: Allocator) !ParsedValue` - [ ] `toTypedValue(comptime T: type, parsed: ParsedValue) T` - [ ] Handle list parsing (comma-separated values) - [ ] Handle enum parsing (string to enum value) - [ ] Add unit tests for value conversions **Acceptance Criteria:** - String to typed value conversion works for all types - Lists properly split on commas - Enums parse from string names - Error handling for invalid values **Estimated Time:** 1 day --- ## Phase 2: Metadata System (Week 1) ### 2.1 Metadata Structures **File:** `src/metadata.zig` **Tasks:** - [ ] Define `ArgumentMetadata` struct - [ ] name, type, default_value_str - [ ] short, long, help, value_name - [ ] is_list flag - [ ] source_location - [ ] modules list (ArrayList) - [ ] Define `ModuleInfo` struct - [ ] name - [ ] arguments list (ArrayList) - [ ] Define `FieldMetadata` struct (for comptime extraction) **Acceptance Criteria:** - Structures compile and are well-documented - Memory management strategy clear **Estimated Time:** 0.5 days --- ### 2.2 Metadata Extraction **File:** `src/metadata.zig` **Tasks:** - [ ] Implement `extractFieldMetadata(comptime T: type, comptime field_name: []const u8)` - [ ] Get `meta` decl if exists - [ ] Extract short/long/help/value_name from meta - [ ] Generate defaults if meta missing - [ ] Convert field name to kebab-case for long form - [ ] Implement `extractDocComment(comptime T: type, comptime field_name: []const u8) []const u8` - [ ] Use doc comments as help text (if available in future Zig) - [ ] Fallback to empty string for now - [ ] Implement `formatDefaultValue(comptime T: type, value: T, allocator: Allocator) ![]const u8` - [ ] Format bool as "true"/"false" - [ ] Format integers as strings - [ ] Format strings as-is - [ ] Format enums as tag names - [ ] Format lists as comma-separated **Acceptance Criteria:** - Can extract metadata from any valid struct - Default values formatted correctly - Missing meta declarations handled gracefully **Estimated Time:** 1-2 days --- ## Phase 3: Core Registry (Week 2) ### 3.1 ArgumentRegistry Basic Structure **File:** `src/ArgumentRegistry.zig` **Tasks:** - [ ] Define `ArgumentRegistry` struct with fields: - [ ] allocator, arena - [ ] arguments (StringHashMap) - [ ] modules (StringHashMap) - [ ] parsed_values (StringHashMap) - [ ] parsed_structs (StringHashMap) - [ ] argv cache - [ ] help_requested flag - [ ] Implement `init(allocator: Allocator) ArgumentRegistry` - [ ] Implement `deinit(self: *ArgumentRegistry) void` - [ ] Clean up all ArrayLists in modules - [ ] Clean up all ArrayLists in arguments - [ ] Deinit hashmaps - [ ] Deinit arena **Acceptance Criteria:** - Registry initializes correctly - No memory leaks (test with MemoryLeakDetector) - All resources cleaned up properly **Estimated Time:** 1 day --- ### 3.2 Help Request Detection **File:** `src/ArgumentRegistry.zig` **Tasks:** - [ ] Implement `isHelpRequested(self: *ArgumentRegistry) bool` - [ ] Cache argv on first call - [ ] Scan for "--help" or "-h" - [ ] Set help_requested flag - [ ] Return cached result on subsequent calls **Acceptance Criteria:** - Help detection works before any parsing - Argv cached for later use - No performance issues with repeated calls **Estimated Time:** 0.5 days --- ### 3.3 Metadata Registration **File:** `src/ArgumentRegistry.zig` **Tasks:** - [ ] Implement `registerMetadata(self: *ArgumentRegistry, comptime T: type, opts: ParseOptions) !void` - [ ] Get or create module entry - [ ] Iterate over struct fields (comptime) - [ ] Extract metadata for each field - [ ] Check for existing arguments (collision detection) - [ ] Error on incompatible type collisions with source locations - [ ] Warn on compatible type collisions - [ ] Add argument to module's list - [ ] Store ArgumentMetadata in registry **Acceptance Criteria:** - Metadata correctly extracted from structs - Compatible collisions allowed with warnings - Incompatible collisions rejected with clear error messages - Source locations captured and displayed in errors **Estimated Time:** 2 days --- ### 3.4 Struct Already Parsed Check **File:** `src/ArgumentRegistry.zig` **Tasks:** - [ ] Implement struct tracking in `parsed_structs` hashmap - [ ] Use `@typeName(T)` as key - [ ] Skip re-registration if already seen **Acceptance Criteria:** - Calling `parse()` twice with same struct is efficient - No duplicate metadata registration **Estimated Time:** 0.5 days --- ## Phase 4: Argument Parsing (Week 2-3) ### 4.1 Argv Parsing Infrastructure **File:** `src/parsing.zig` **Tasks:** - [ ] Implement `parseArgv(self: *ArgumentRegistry) !void` - [ ] Get argv via `std.process.argsAlloc()` if not cached - [ ] Skip program name - [ ] Iterate over arguments - [ ] Dispatch to appropriate parser - [ ] Implement `parseArg(self: *ArgumentRegistry, arg: []const u8) !void` - [ ] Handle `--long-name=value` format - [ ] Handle `--long-name value` format (next arg) - [ ] Handle `--flag` (boolean) format - [ ] Look up argument metadata - [ ] Parse value according to type - [ ] Store in parsed_values - [ ] Implement `parseShortArg(self: *ArgumentRegistry, short: u8) !void` - [ ] Look up by short character - [ ] Handle value if required - [ ] Handle flag if boolean **Acceptance Criteria:** - All argument formats parsed correctly - Unknown arguments produce clear errors - Values parsed according to type - Boolean flags don't require values **Estimated Time:** 2 days --- ### 4.2 Value Parsing **File:** `src/parsing.zig` **Tasks:** - [ ] Implement integer parsing with error handling - [ ] Implement boolean parsing ("true"/"false", "1"/"0") - [ ] Implement string parsing (already a string) - [ ] Implement list parsing (split on comma) - [ ] Implement enum parsing (string to enum tag) - [ ] Handle parsing errors with useful messages **Acceptance Criteria:** - All types parse correctly from strings - Clear errors for invalid values - Edge cases handled (empty strings, invalid numbers, etc.) **Estimated Time:** 1 day --- ### 4.3 Struct Reconstruction **File:** `src/ArgumentRegistry.zig` **Tasks:** - [ ] Implement `reconstructStruct(self: *ArgumentRegistry, comptime T: type) T` - [ ] Create uninitialized struct - [ ] Iterate over fields (comptime) - [ ] Look up parsed value by long name - [ ] Convert ParsedValue to field type - [ ] Fall back to default if not parsed - [ ] Return completed struct **Acceptance Criteria:** - Structs correctly populated with parsed values - Defaults used when arguments not provided - Type conversions work correctly - All fields properly initialized **Estimated Time:** 1 day --- ### 4.4 Main parse() Function **File:** `src/ArgumentRegistry.zig` **Tasks:** - [ ] Implement `parse(self: *ArgumentRegistry, comptime T: type, opts: ParseOptions) !T` - [ ] Check if already parsed (use parsed_structs) - [ ] If not, register metadata - [ ] Parse argv (only new arguments) - [ ] Reconstruct and return struct - [ ] Mark struct as parsed **Acceptance Criteria:** - Complete parse flow works end-to-end - Lazy parsing only processes new arguments - Subsequent calls return cached results efficiently **Estimated Time:** 1 day --- ## Phase 5: Help Generation (Week 3) ### 5.1 Help Text Formatting **File:** `src/help.zig` **Tasks:** - [ ] Implement `getUsageAlloc(self: *ArgumentRegistry, allocator: Allocator) ![]const u8` - [ ] Write header ("Usage: [OPTIONS]") - [ ] Write global options (--help) - [ ] Group arguments by module - [ ] Format each argument: - [ ] `-s, --long-name ` - [ ] Help text - [ ] Default value - [ ] Return allocated string **Acceptance Criteria:** - Help text is well-formatted and readable - Arguments grouped by module - Defaults shown for all arguments - Short and long forms displayed correctly **Estimated Time:** 1 day --- ### 5.2 Help Text Alignment **File:** `src/help.zig` **Tasks:** - [ ] Calculate maximum width of argument specifications - [ ] Align help text in columns - [ ] Handle line wrapping for long help text - [ ] Ensure consistent spacing **Acceptance Criteria:** - Help text looks professional - Columns aligned nicely - Readable on standard terminal widths **Estimated Time:** 0.5 days --- ## Phase 6: Public API (Week 3) ### 6.1 Main Module Exports **File:** `src/main.zig` **Tasks:** - [ ] Export `ArgumentRegistry` - [ ] Export `ArgumentType` - [ ] Export `ParsedValue` - [ ] Export helper types (ParseOptions, etc.) - [ ] Add top-level documentation - [ ] Define version constant **Acceptance Criteria:** - All public types accessible - API is clean and well-documented - Version information available **Estimated Time:** 0.5 days --- ### 6.2 Global Registry Helper **File:** `src/main.zig` **Tasks:** - [ ] Consider providing helper to initialize global registry - [ ] Document pattern for global usage - [ ] Provide example code **Acceptance Criteria:** - Clear guidance on using global singleton - Thread safety considerations documented **Estimated Time:** 0.5 days --- ## Phase 7: Testing (Week 4) ### 7.1 Unit Tests **Files:** `tests/*.zig` **Tasks:** - [ ] Test type detection and conversion - [ ] Test metadata extraction - [ ] Test argument parsing (all formats) - [ ] Test collision detection (compatible and incompatible) - [ ] Test help generation - [ ] Test struct reconstruction - [ ] Test list parsing - [ ] Test enum parsing - [ ] Test error conditions **Acceptance Criteria:** - 100% code coverage of core logic - All edge cases tested - Clear test names and documentation **Estimated Time:** 2 days --- ### 7.2 Integration Tests **Files:** `tests/*.zig` **Tasks:** - [ ] Test full parse cycle with multiple structs - [ ] Test module registration order independence - [ ] Test argv caching behavior - [ ] Test help request before parsing - [ ] Test help text persistence workflow **Acceptance Criteria:** - End-to-end workflows tested - Multiple modules interacting correctly - Real-world scenarios covered **Estimated Time:** 1 day --- ### 7.3 Memory Leak Testing **Files:** `tests/*.zig` **Tasks:** - [ ] Wrap all tests with memory leak detection - [ ] Test cleanup paths (deinit) - [ ] Test error paths (proper cleanup on errors) - [ ] Verify arena allocator usage **Acceptance Criteria:** - Zero memory leaks in all tests - All allocations properly freed **Estimated Time:** 0.5 days --- ## Phase 8: Examples and Documentation (Week 4) ### 8.1 Simple Example **File:** `examples/simple.zig` **Tasks:** - [ ] Single struct with basic types - [ ] Parse and print values - [ ] Show help usage - [ ] Document every step **Acceptance Criteria:** - Works as minimal starting point - Clear and easy to understand **Estimated Time:** 0.5 days --- ### 8.2 Game Engine Example **File:** `examples/game_engine.zig` **Tasks:** - [ ] Multiple modules (Engine, Physics, Audio, Renderer) - [ ] Each module has its own Args struct - [ ] Show scattered parsing pattern - [ ] Generate help text - [ ] Demonstrate compatible collisions **Acceptance Criteria:** - Realistic game engine scenario - Shows plugin architecture usage - Help text properly grouped **Estimated Time:** 1 day --- ### 8.3 Persistence Example **File:** `examples/persistence.zig` **Tasks:** - [ ] Generate help text after parsing - [ ] Write to file - [ ] Show embedding with @embedFile - [ ] Fast --help response **Acceptance Criteria:** - Demonstrates novel persistence feature - Shows workflow for production usage **Estimated Time:** 0.5 days --- ### 8.4 README and API Documentation **Files:** `README.md`, doc comments **Tasks:** - [ ] Write comprehensive README - [ ] What is zargs? - [ ] Why use it? - [ ] Quick start guide - [ ] Design philosophy - [ ] Comparison to alternatives - [ ] Document all public APIs with doc comments - [ ] Add usage examples to doc comments - [ ] Document design decisions **Acceptance Criteria:** - README is compelling and informative - All public APIs documented - Examples included in docs **Estimated Time:** 1 day --- ## Phase 9: Build System (Week 4) ### 9.1 Build.zig Setup **File:** `build.zig` **Tasks:** - [ ] Define library module - [ ] Add test step - [ ] Add example build steps - [ ] Add install step - [ ] Configure for Zig 0.14 **Acceptance Criteria:** - `zig build` compiles library - `zig build test` runs all tests - `zig build run-simple` runs simple example - Works with Zig 0.14 **Estimated Time:** 0.5 days --- ### 9.2 Integration with Backlog Engine **File:** Integration into main project **Tasks:** - [ ] Import as lib/zargs module - [ ] Make available to engine modules - [ ] Test with actual engine code - [ ] Document engine-specific patterns **Acceptance Criteria:** - Engine can use zargs - Works with existing build system **Estimated Time:** 0.5 days --- ## Phase 10: Polish and Release (Week 5) ### 10.1 Error Messages **Tasks:** - [ ] Review all error messages - [ ] Ensure helpful and actionable - [ ] Include context (argument name, module, source location) - [ ] Format consistently **Acceptance Criteria:** - User-friendly error messages - Easy to debug issues **Estimated Time:** 0.5 days --- ### 10.2 Performance Testing **Tasks:** - [ ] Benchmark parsing overhead - [ ] Benchmark help generation - [ ] Profile memory usage - [ ] Optimize hot paths if needed **Acceptance Criteria:** - Parsing overhead negligible - Help generation fast - Memory usage reasonable **Estimated Time:** 1 day --- ### 10.3 Edge Cases **Tasks:** - [ ] Test with empty argv - [ ] Test with no arguments defined - [ ] Test with only --help - [ ] Test with very long argument lists - [ ] Test with unicode in arguments - [ ] Test with special characters **Acceptance Criteria:** - No crashes on edge cases - Reasonable behavior **Estimated Time:** 0.5 days --- ### 10.4 Final Review **Tasks:** - [ ] Code review entire implementation - [ ] Check for TODOs - [ ] Verify all tests pass - [ ] Run formatter - [ ] Check for memory leaks - [ ] Update documentation **Acceptance Criteria:** - Code is production-ready - No known issues **Estimated Time:** 1 day --- ## Timeline Summary | Phase | Duration | Milestone | |-------|----------|-----------| | 1. Core Type System | 2-3 days | Type detection working | | 2. Metadata System | 1.5-2.5 days | Metadata extraction working | | 3. Core Registry | 4 days | Registry structure complete | | 4. Argument Parsing | 5 days | End-to-end parsing working | | 5. Help Generation | 1.5 days | Help text generation working | | 6. Public API | 1 day | API finalized | | 7. Testing | 3.5 days | Full test coverage | | 8. Examples & Docs | 3 days | Documentation complete | | 9. Build System | 1 day | Build integration complete | | 10. Polish & Release | 3 days | Production ready | **Total Estimated Time:** ~25 days (5 weeks) ## Success Criteria - [ ] All unit tests pass - [ ] All integration tests pass - [ ] Zero memory leaks - [ ] All examples run correctly - [ ] Documentation complete and clear - [ ] Can parse arguments from multiple modules - [ ] Compatible collisions work - [ ] Incompatible collisions error appropriately - [ ] Help text generation works - [ ] Help text persistence workflow demonstrated - [ ] Integration with Backlog engine successful ## Risks and Mitigations | Risk | Impact | Mitigation | |------|--------|------------| | Comptime complexity too high | High | Start simple, iterate; use runtime where needed | | Memory management issues | High | Test early with leak detection; use arena allocator | | Type system edge cases | Medium | Comprehensive type testing; clear error messages | | Help text formatting tricky | Low | Reference existing tools; iterate on format | | Integration issues | Medium | Test integration early in Phase 9 | ## Open Questions 1. Should we support positional arguments in v2? (deferred to v1 feedback) 2. Should we support config file loading? (separate feature, later) 3. Should we support environment variable fallback? (separate feature, later) 4. What about shell completion generation? (v2 feature) 5. How to handle argument value validation? (v2 feature - validators) ## Dependencies - Zig 0.14 - No external dependencies (pure std lib) ## Testing Strategy 1. **Unit tests** - Test individual components in isolation 2. **Integration tests** - Test component interactions 3. **Example tests** - Ensure examples compile and run 4. **Memory tests** - Verify no leaks with GeneralPurposeAllocator 5. **Manual testing** - Test with Backlog engine integration ## Notes - Keep implementation simple and focused on core use case - Prioritize game engine / plugin architecture scenario - Document design decisions and tradeoffs - Write tests alongside implementation (TDD where appropriate) - Get feedback early from engine integration