Skip to content

Latest commit

 

History

History
360 lines (269 loc) · 10.6 KB

File metadata and controls

360 lines (269 loc) · 10.6 KB

Contributing to Zeitgeist

Thank you for your interest in contributing to Zeitgeist! This guide will help you get started.

Table of Contents

Development Setup

Prerequisites

Building from Source

git clone https://github.com/bkataru/zeitgeist
cd zeitgeist

# Debug build (faster compilation, slower runtime)
zig build

# Release build (slower compilation, optimized runtime)
zig build -Doptimize=ReleaseFast

The executable will be available at zig-out/bin/zeitgeist (and zig-out/bin/zg as a short alias).

Building and Testing

Build Commands

# Debug build
zig build

# Release build (optimized)
zig build -Doptimize=ReleaseFast

# Install to a prefix (e.g., ~/.local)
zig build install --prefix ~/.local

Test Commands

# Run all unit tests (247 tests)
zig build test --summary all

# Run integration tests (30 tests)
zig build integration --summary all

# Run both test suites
zig build test --summary all && zig build integration --summary all

# Run specific test by name
zig build test -- --test-filter="parse JSON"

Running the CLI

# Run directly via build system
zig build run -- [OPTIONS] [PATH]

# Run with verbose output
zig build run -- --verbose .

# Run with specific options
zig build run -- -s markdown -o output.md ./src

# Or use the built executable directly
./zig-out/bin/zeitgeist [OPTIONS] [PATH]

Code Style

Naming Conventions

  • Functions and variables: snake_case
  • Types and structs: PascalCase
  • Constants: SCREAMING_SNAKE_CASE or snake_case (context-dependent)
  • File names: snake_case.zig

Best Practices

  • Follow Zig standard library conventions
  • Add doc comments (///) for all public functions and types
  • Keep functions focused and small (< 50 lines preferred)
  • Handle errors explicitly - never discard errors with _
  • Use defer for cleanup to ensure resources are freed
  • Prefer slices over pointers when possible
  • Use std.mem.Allocator for all dynamic allocations

Example

/// Processes a file and returns its token count.
/// Returns an error if the file cannot be read.
pub fn processFile(allocator: std.mem.Allocator, path: []const u8) !usize {
    const file = try std.fs.cwd().openFile(path, .{});
    defer file.close();
    
    const content = try file.readToEndAlloc(allocator, max_file_size);
    defer allocator.free(content);
    
    return countTokens(content);
}

Project Structure

Note: The build produces two executables: zeitgeist and zg (short alias). Both are identical in functionality.

zeitgeist/
├── src/
│   ├── cli/                    # Command-line interface
│   │   └── main.zig            # CLI entry point (~2600 lines)
│   └── lib/                    # Core library modules
│       ├── lib.zig             # Library exports (public API)
│       ├── config.zig          # Core Config struct
│       ├── config_file.zig     # Config file parsing (JSON/YAML/TOML)
│       ├── scanner.zig         # Directory scanning, tree building
│       ├── processor.zig       # File processing, encoding detection
│       ├── output.zig          # Output generation (XML/MD/JSON/Text)
│       ├── filter.zig          # Glob patterns, gitignore parsing
│       ├── git.zig             # Git integration (sorting, diffs, logs)
│       ├── security.zig        # Secret/API key scanning
│       ├── tokenizer.zig       # Token counting (BPE approximation)
│       ├── chunker.zig         # Output splitting for LLM limits
│       ├── category.zig        # File categorization system
│       ├── template.zig        # Custom output templates
│       ├── toml.zig            # TOML parser
│       ├── compress.zig        # Content compression
│       ├── notebook.zig        # Jupyter notebook conversion
│       ├── remote.zig          # Remote repository support
│       ├── updater.zig         # Self-update functionality
│       ├── completions.zig     # Shell completion generation
│       └── mcp.zig             # MCP server implementation
├── tests/
│   └── integration.zig         # Integration tests (30 tests)
├── schema/
│   └── zeitgeist.schema.json   # JSON Schema for config validation
├── examples/
│   └── full-config.json        # Complete example configuration
├── docs/
│   ├── CONFIGURATION.md        # Configuration reference
│   ├── API.md                  # Library API documentation
│   └── references/             # Internal references
├── build.zig                   # Build configuration (creates zeitgeist + zg)
├── build.zig.zon               # Package dependencies
├── CHANGELOG.md                # Version history
├── LICENSE                     # MIT License
└── README.md                   # Project documentation

Key Modules

Module Responsibility
scanner.zig Directory traversal, tree building, file discovery
processor.zig File reading, encoding detection, content processing
output.zig Format-specific output generation
filter.zig Glob matching, gitignore parsing, include/exclude logic
config_file.zig JSON, YAML, and TOML configuration parsing
security.zig Regex-based secret detection
remote.zig GitHub/GitLab/Bitbucket API integration

Adding New Features

Process

  1. Open an issue first - Discuss the use case and proposed implementation
  2. Design the API - Consider how the feature fits with existing code
  3. Implement the feature in the appropriate module
  4. Add comprehensive tests (minimum 3-5 tests per feature)
  5. Update documentation:
    • Add doc comments to new public APIs
    • Update README.md if user-facing
    • Update CHANGELOG.md with the changes
    • Update schema if adding config options
  6. Test with real codebases before submitting

Adding a CLI Flag

  1. Add the option to the Options struct in src/cli/main.zig
  2. Add argument parsing in the main argument loop
  3. Add help text in the printHelp function
  4. Wire the option to the appropriate PackConfig field
  5. Add unit tests for argument parsing

Adding a Config Option

  1. Add the field to the appropriate struct in src/lib/config_file.zig
  2. Add parsing logic for JSON, YAML, and TOML formats
  3. Update schema/zeitgeist.schema.json
  4. Update examples/full-config.json
  5. Add tests for each config format

Testing Guidelines

Unit Tests

Add unit tests at the bottom of source files using Zig's built-in test blocks:

test "myFunction handles empty input" {
    const allocator = std.testing.allocator;
    const result = try myFunction(allocator, "");
    defer allocator.free(result);
    try std.testing.expectEqual(@as(usize, 0), result.len);
}

test "myFunction handles unicode" {
    const allocator = std.testing.allocator;
    const result = try myFunction(allocator, "こんにちは");
    defer allocator.free(result);
    try std.testing.expect(result.len > 0);
}

Integration Tests

For end-to-end testing, add to tests/integration.zig:

test "pack directory with custom config" {
    const allocator = std.testing.allocator;
    
    // Create test directory structure
    var tmp = std.testing.tmpDir(.{});
    defer tmp.cleanup();
    
    // Write test files
    try tmp.dir.writeFile("test.zig", "const x = 1;");
    
    // Run the packer
    var packer = try Packer.init(allocator, .{});
    defer packer.deinit();
    
    const result = try packer.pack(tmp.dir.path);
    defer allocator.free(result);
    
    // Verify output
    try std.testing.expect(std.mem.indexOf(u8, result, "test.zig") != null);
}

Test Coverage Expectations

  • New features: Minimum 3-5 tests covering normal, edge, and error cases
  • Bug fixes: At least 1 test that reproduces and verifies the fix
  • Refactoring: Existing tests should continue to pass

Pull Request Process

Before Submitting

  1. Fork the repository and create your feature branch from main
  2. Ensure all tests pass:
    zig build test --summary all && zig build integration --summary all
  3. Update documentation as needed
  4. Update CHANGELOG.md with your changes under [Unreleased]

PR Description

Include in your PR description:

  • Summary: What does this PR do?
  • Motivation: Why is this change needed?
  • Testing: How was this tested?
  • Breaking changes: Any breaking changes? (for library API)

Commit Message Guidelines

type: short description (under 72 chars)

Longer description if needed. Explain the what and why,
not the how (the code shows that).

Fixes #123

Types: feat, fix, docs, refactor, test, chore

Examples:

  • feat: add TOML config support
  • fix: handle UTF-16 BOM in file detection
  • docs: update README with new CLI options
  • refactor: simplify token counting logic

Reporting Issues

Before Reporting

  • Search existing issues to avoid duplicates
  • Check if the issue persists with the latest version
  • Try to reproduce with a minimal example

Issue Template

**Environment**
- OS: [e.g., Windows 11, macOS 14, Ubuntu 24.04]
- Zig version: [output of `zig version`]
- Zeitgeist version: [output of `zeitgeist --version`]

**Description**
A clear description of the bug or feature request.

**Steps to Reproduce**
1. Run `zeitgeist ...`
2. See error

**Expected Behavior**
What you expected to happen.

**Actual Behavior**
What actually happened.

**Additional Context**
Error messages, stack traces, screenshots, etc.

Code of Conduct

  • Be respectful and constructive in discussions
  • Focus on the technical merits of contributions
  • Help others learn and grow
  • Assume good intentions

License

By contributing to Zeitgeist, you agree that your contributions will be licensed under the MIT License.

MIT License
Copyright (c) 2026 bkataru (Baalateja Kataru)

See the LICENSE file for details.

Questions?

If you have questions about contributing:

  1. Check existing issues and discussions
  2. Open a new issue with the question label
  3. Be specific about what you're trying to accomplish