Contributing
Thank you for considering contributing to Zeph.
Getting Started
- Fork the repository
- Clone your fork and create a branch from
main - Install Rust 1.88+ (Edition 2024 required, resolver 3)
- Install sccache for build caching (optional but recommended)
- Run
cargo buildto verify the setup - 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
| Crate | Purpose |
|---|---|
zeph-common | Shared primitives: Secret, VaultError, common types |
zeph-config | Pure-data configuration types, TOML loader, env overrides, migration |
zeph-vault | VaultProvider trait + env and age-encrypted backends |
zeph-db | Database abstraction (SQLite + PostgreSQL) |
zeph-llm | LlmProvider trait, Ollama + Claude + OpenAI + Gemini + Candle backends |
zeph-memory | SQLite + Qdrant memory, semantic search, document loaders |
zeph-tools | ToolExecutor trait, shell sandbox, file ops, web scraper |
zeph-skills | SKILL.md parser, registry, embedding matcher, hot-reload |
zeph-index | AST-based code indexing, semantic retrieval, repo map (always-on) |
zeph-sanitizer | Content sanitization, PII filter, exfiltration guard |
zeph-experiments | Autonomous experiment engine, LLM-as-judge evaluation |
zeph-subagent | Sub-agent lifecycle, grants, transcripts, hooks |
zeph-orchestration | DAG-based task orchestration, planner, router, aggregator |
zeph-core | Agent loop, AppBuilder bootstrap, context builder, metrics |
zeph-channels | Telegram, Discord, Slack adapters |
zeph-mcp | MCP client via rmcp, multi-server lifecycle (optional) |
zeph-acp | ACP server for IDE integration (optional) |
zeph-a2a | A2A protocol client + server (optional) |
zeph-gateway | HTTP webhook gateway (optional) |
zeph-scheduler | Cron task scheduler with SQLite persistence (optional) |
zeph-tui | ratatui 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
- Read the relevant specification in
specs/— every subsystem has a correspondingspec.md. Start withspecs/constitution.mdfor project-wide invariants. - If your change affects an existing subsystem, open the matching spec and review the
## Key InvariantsandNEVERsections. These are hard constraints. - 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
- 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.
- If no spec exists for the area you are changing, create one in
specs/<area>/spec.mdbefore 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
- Create a feature branch:
feat/<scope>/<description>orfix/<scope>/<description> - Keep changes focused — one logical change per PR
- Add tests for new functionality
- Ensure all checks pass:
cargo +nightly fmt,cargo clippy,cargo nextest run --lib --bins - Write a clear PR description following the template
- 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 fmtfor 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.