19 KiB
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
ArgumentTypeenum with all supported typesbool,u8,u16,u32,u64i8,i16,i32,i64string([]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
- Handle
- 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
ParsedValuetagged union - Implement conversion functions:
fromString(arg_type: ArgumentType, s: []const u8, allocator: Allocator) !ParsedValuetoTypedValue(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
ArgumentMetadatastruct- name, type, default_value_str
- short, long, help, value_name
- is_list flag
- source_location
- modules list (ArrayList)
- Define
ModuleInfostruct- name
- arguments list (ArrayList)
- Define
FieldMetadatastruct (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
metadecl if exists - Extract short/long/help/value_name from meta
- Generate defaults if meta missing
- Convert field name to kebab-case for long form
- Get
- 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
ArgumentRegistrystruct 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_structshashmap - 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
- Get argv via
- Implement
parseArg(self: *ArgumentRegistry, arg: []const u8) !void- Handle
--long-name=valueformat - Handle
--long-name valueformat (next arg) - Handle
--flag(boolean) format - Look up argument metadata
- Parse value according to type
- Store in parsed_values
- Handle
- 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 <VALUE>- 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 buildcompiles libraryzig build testruns all testszig build run-simpleruns 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
- Should we support positional arguments in v2? (deferred to v1 feedback)
- Should we support config file loading? (separate feature, later)
- Should we support environment variable fallback? (separate feature, later)
- What about shell completion generation? (v2 feature)
- How to handle argument value validation? (v2 feature - validators)
Dependencies
- Zig 0.14
- No external dependencies (pure std lib)
Testing Strategy
- Unit tests - Test individual components in isolation
- Integration tests - Test component interactions
- Example tests - Ensure examples compile and run
- Memory tests - Verify no leaks with GeneralPurposeAllocator
- 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