Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Contributing

Thank you for considering contributing to Zeph.

Getting Started

  1. Fork the repository
  2. Clone your fork and create a branch from main
  3. Install Rust 1.88+ (Edition 2024 required, resolver 3)
  4. Install sccache for build caching (optional but recommended)
  5. Run cargo build to verify the setup
  6. Install cargo-nextest for running tests

Development

Build

cargo build

Test

# Run unit tests only (exclude integration tests)
cargo nextest run --workspace --lib --bins

# Run all tests including integration tests (requires Docker)
cargo nextest run --workspace --profile ci

Nextest profiles (.config/nextest.toml):

  • default: Runs all tests (unit + integration)
  • ci: CI environment, runs all tests with JUnit XML output for reporting

Integration Tests

Integration tests use testcontainers-rs to automatically spin up Docker containers for external services (Qdrant, etc.).

Prerequisites: Docker must be running on your machine.

# Run only integration tests
cargo nextest run --workspace --test '*integration*'

# Run unit tests only (skip integration tests)
cargo nextest run --workspace --lib --bins

# Run all tests
cargo nextest run --workspace

Integration test files are located in each crate’s tests/ directory and follow the *_integration.rs naming convention.

Lint

cargo +nightly fmt --check
cargo clippy --all-targets

Benchmarks

cargo bench -p zeph-memory --bench token_estimation
cargo bench -p zeph-skills --bench matcher
cargo bench -p zeph-core --bench context_building

Coverage

cargo llvm-cov --all-features --workspace

Workspace Structure

CratePurpose
zeph-commonShared primitives: Secret, VaultError, common types
zeph-configPure-data configuration types, TOML loader, env overrides, migration
zeph-vaultVaultProvider trait + env and age-encrypted backends
zeph-dbDatabase abstraction (SQLite + PostgreSQL)
zeph-llmLlmProvider trait, Ollama + Claude + OpenAI + Gemini + Candle backends
zeph-memorySQLite + Qdrant memory, semantic search, document loaders
zeph-toolsToolExecutor trait, shell sandbox, file ops, web scraper
zeph-skillsSKILL.md parser, registry, embedding matcher, hot-reload
zeph-indexAST-based code indexing, semantic retrieval, repo map (always-on)
zeph-sanitizerContent sanitization, PII filter, exfiltration guard
zeph-experimentsAutonomous experiment engine, LLM-as-judge evaluation
zeph-subagentSub-agent lifecycle, grants, transcripts, hooks
zeph-orchestrationDAG-based task orchestration, planner, router, aggregator
zeph-coreAgent loop, AppBuilder bootstrap, context builder, metrics
zeph-channelsTelegram, Discord, Slack adapters
zeph-mcpMCP client via rmcp, multi-server lifecycle (optional)
zeph-acpACP server for IDE integration (optional)
zeph-a2aA2A protocol client + server (optional)
zeph-gatewayHTTP webhook gateway (optional)
zeph-schedulerCron task scheduler with SQLite persistence (optional)
zeph-tuiratatui TUI dashboard with real-time metrics (optional)

Spec-Driven Development

Zeph follows a spec-driven development process. Code changes come after spec changes, not before.

Before writing any code

  1. Read the relevant specification in specs/ — every subsystem has a corresponding spec.md. Start with specs/constitution.md for project-wide invariants.
  2. If your change affects an existing subsystem, open the matching spec and review the ## Key Invariants and NEVER sections. These are hard constraints.
  3. Propose the spec change first. Open a GitHub issue or discussion describing:
    • What you want to change and why
    • Which spec sections are affected
    • Whether any invariants need to be updated or explicitly overridden
  4. Once the spec change is agreed upon, update the spec file and open a PR that includes both the spec update and the implementation together.
  5. If no spec exists for the area you are changing, create one in specs/<area>/spec.md before writing code. Use the existing specs as a template.

This process ensures that architectural decisions are made deliberately and documented before they become code — not reverse-engineered from a diff after the fact.

Pull Requests

  1. Create a feature branch: feat/<scope>/<description> or fix/<scope>/<description>
  2. Keep changes focused — one logical change per PR
  3. Add tests for new functionality
  4. Ensure all checks pass: cargo +nightly fmt, cargo clippy, cargo nextest run --lib --bins
  5. Write a clear PR description following the template
  6. If the PR touches a specced subsystem, reference the relevant specs/ file and confirm that the implementation is compliant with the current spec

Commit Messages

  • Use imperative mood: “Add feature” not “Added feature”
  • Keep the first line under 72 characters
  • Reference related issues when applicable

Code Style

  • Follow workspace clippy lints (pedantic enabled)
  • Use cargo +nightly fmt for formatting
  • Avoid unnecessary comments — code should be self-explanatory
  • Comments are only for cognitively complex blocks

License

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