Ocelot is a process supervisor and init system written in Rust.
This project uses Nix Flakes for development environment. We strongly recommend using Nix to ensure consistent tooling across all contributors.
# Enter the development environment
nix develop
# Build the project
cargo build
# Run tests
cargo nextest rundirenv automatically loads the Nix environment when you enter the project directory.
- Install direnv:
nix profile install nixpkgs#direnv - Add to your shell (bash/zsh/fish)
- Allow direnv in the project directory:
direnv allow
Then the development environment will load automatically every time you enter the project.
If you don't use Nix, you need to install the following tools manually:
Required:
- Rust (see
rust-toolchain.tomlfor version) - Cargo
- cargo-nextest
- pkg-config
- libgit2
Recommended (for formatting/linting):
- rustfmt
- treefmt
- nixfmt
- shfmt
- shellcheck
- taplo
- hclfmt
- prettier
# Clone the project
git clone https://github.com/xrelkd/ocelot.git
cd ocelot
# Build
cargo build
cargo build --release
# Run
cargo run --package ocelot# Debug build
cargo build
# Release build
cargo build --release
# Run the main binary
cargo run --package ocelot# Run tests with cargo test
cargo test
# Or use cargo-nextest (faster, used in CI)
cargo nextest run
cargo nextest run --release
# Run all tests with retries (preferred wrapper command)
cargo nextest-allAlways run these before creating a commit:
# Format code
cargo fmt --all --check
treefmt # Format all file types (Rust, JS, JSON, TOML, Nix, Shell, HCL)
nix fmt # If using Nix
# Run lints (fix all warnings/errors)
cargo clippy-all # Wrapper: cargo clippy --workspace --all-targets
cargo clippy-all --fix # Auto-fix where possibleKeep commits clean:
- Fix all lints and compilation errors in the same commit as your feature/fix
- Do NOT create separate commits for lint fixes
- Keep commit messages concise and meaningful
Create feature/fix branches from develop:
# Feature branch
git checkout -b feat/my-new-feature develop
# Fix branch
git checkout -b fix/bug-description developSupported prefixes: feat/*, feature/*, fix/*, hotfix/*, release/*, ci/*
- Run formatters (
cargo fmt --all --check,treefmt, ornix fmt) - Run lints and fix all warnings/errors (
cargo clippy-all --fix) - Ensure tests pass (
cargo nextest runorcargo nextest-all) - Push your branch to your fork
- Create a PR targeting the
developbranch - Ensure all CI checks pass
- Keep commits clean, concise, and follow the commit message convention
Tip
See AGENTS.md for detailed coding assistant guidelines and conventions.md for comprehensive Rust coding conventions.
This project follows Conventional Commits specification. Commit messages are validated by commitlint in CI.
<type>(<scope>): <description> (#PR)
| Type | Description |
|---|---|
feat |
New feature |
fix |
Bug fix |
refactor |
Code refactoring |
perf |
Performance improvement |
docs |
Documentation updates |
style |
Code formatting (no logic changes) |
ci |
CI/CD modifications |
chore |
Maintenance tasks |
build |
Build system or dependencies |
test |
Test additions or improvements |
The scope is optional but recommended when the change affects a specific component.
Each commit should only affect one scope. If your PR modifies multiple components, create separate commits for each one.
Good:
# Commit 1
fix(crates/entry): rename `splice` arguments
# Commit 2
fix(crates/supervise): fix PID 1 warning messageBad:
# Don't do this
fix: fix lints and errors in crates/entry and crates/superviseLint fixes should be part of the feature commit. Do not create separate commits for fixing lints or compilation errors.
| Scope | Description |
|---|---|
ocelot |
Main binary crate |
crates/entry |
Process supervisor crate |
crates/supervise |
Advanced supervisor crate |
crates/idle |
Minimalist PID 1 crate |
crates/zombie |
Zombie process generator crate |
crates/test-utils |
Shared test utilities crate |
readme |
README documentation |
agents |
AGENTS.md file |
gitignore |
.gitignore updates |
actions |
GitHub Actions workflows |
nix |
Nix/NixOS modules |
Some commits don't require a scope:
style: apply formatterchore: update Rust formatterbuild(deps): update Cargo.lock
# Feature in multiple scopes - create separate commits
feat(crates/supervise): add LZ4 log compression
feat(ocelot): add log rotation compression
# Bug Fix
fix(crates/supervise): reset signal handlers before `exec`
# Refactor
refactor(ocelot): restructure configuration modules
# Performance
perf(crates/supervise): inline handle event method
# Documentation
docs(readme): update the `README.md` file
# CI/CD
ci(actions): update `prettier` installation path
# Chore
chore(gitignore): add ignore rules for AI tool configs
# Style (no scope needed)
style: apply formatter
# Dependency Update (usually automated)
build(deps): bump lz4_flex from 0.11.6 to 0.13.0 (#43)When submitting a PR that touches multiple scopes, use multiple commits:
# If your PR modifies both crates/entry and crates/supervise
fix(crates/entry): rename `splice` arguments
fix(crates/supervise): fix PID 1 warning message
# Then merge with "Merge pull request #123"Always reference the PR number when applicable:
feat(crates/supervise): add configurable termination grace period to reaper (#21)
The Nix devshell provides wrapper commands that set appropriate defaults:
cargo clippy-all # cargo clippy --workspace --all-targets
cargo nextest-all # cargo nextest run with retries (NEXTEST_RETRIES=5)
cargo test-all # Run all tests including ignored
cargo doc-all # cargo doc --workspace --no-deps --bins --all-featuresGenerate shell completions for your preferred shell:
cargo run -- completions zsh > /etc/zsh/completions/_ocelot
cargo run -- completions bash > /etc/bash_completion.d/ocelot
cargo run -- completions fish > ~/.config/fish/completions/ocelot.fish