Files
kappa/CONTRIBUTING.md
T
huntedbytheirs 70d59a3f9c
CI / build-and-test (push) Successful in 56s
comma
2026-08-17 22:52:29 -04:00

146 lines
5.0 KiB
Markdown

# Contributing to kappa
We're building a package manager that doesn't care about your init system,
your bootloader, or your life choices. If that sounds like your kind of
project, keep reading.
## The rules
These aren't guidelines. They're the deal.
### 1. C++23, or don't bother
We compile with Clang, `-std=c++23`, and zero warnings. If your code needs a
polyfill for `std::format` or can't handle designated initializers, it
doesn't belong here. The standard library is your only dependency. Zero
external C++ libraries. Not even Boost.
```cpp
// ✓ yes
auto msg = std::format("building {} (depth={})", name, depth);
// ✗ no
auto msg = fmt::format("building {} (depth={})", name, depth);
```
### 2. Every new module mirrors the existing structure
```
include/kappa/{module}/
├── types.hpp # enums, structs, parse/validate declarations
├── {feature}.hpp # public interface
src/{module}/
├── types.cpp # implementations
├── backend_a.cpp # per-variant generators
├── backend_b.cpp
└── install.cpp # dispatch + orchestration
```
If you're adding a feature, look at `src/service/` or `src/boot/` for the
pattern. If your new module doesn't look like those, you're doing it wrong.
### 3. Never suppress type safety
There is no `as any`, no `@ts-ignore`, no `reinterpret_cast` abuse, and
no `void*` unless you're talking to the kernel. If the type system is
fighting you, you're fighting the design. Fix the design.
### 4. Use the namespace. All of it.
```cpp
namespace kappa::module {
// everything goes here
} // namespace kappa::module
```
No `using namespace std;` at file scope. No anonymous namespaces for
functions that are used across files — extract to `util.hpp` instead.
### 5. Thread safety is not optional
The scheduler is multithreaded. If you touch shared state, you own the
lock. `std::mutex`, `std::atomic`, `std::condition_variable` — use them
correctly or don't use them at all. If you don't know what `memory_order`
means, stay out of the scheduler.
### 6. Tests are shell scripts.
Integration tests live in three suites. If you add a subcommand, add a test.
```sh
./test.sh # 30 tests — DSL parsing, config, services, init systems
./test-init-switch.sh # 23 tests — init-switching, rebuild impact, bootloaders
./test-full.sh # 85 tests — CLI, all keywords, repos, add/remove,
# resolver conflicts, deptrees, build, env ops,
# index generation, --root, imports, doctor, and more
```
All three must pass. CI enforces this on every push to `main`.
### 7. Backward compatibility is mandatory
The `.kap` DSL is the contract. You can add keywords. You cannot remove
them. You can extend syntax. You cannot break existing configs. If your
change means someone's `config.kap` stops parsing, it doesn't ship.
## How to contribute
### Pick something
Good first issues:
- Adding a 6th init system backend (we have 5: systemd, openrc, s6, runit, dinit)
- Adding a 3rd bootloader backend (we have 2: grub, limine)
- Improving the `kappa doctor` diagnostics for package recipes
- Adding `--features` / `--config` flags to `kappa add`
- Shell completion scripts (bash, zsh, fish)
Ambitious issues:
- Binary package support (pre-built caches)
- Remote build farm (distcc-style)
- Signed package verification with index signing
- Filesystem overlay activation (like Nix profiles)
- Transitive dependency resolution (auto-including deps not in config)
### Send a PR
1. Fork the repo
2. Create a branch: `feat/my-thing` or `fix/my-bug`
3. Write code that follows the rules above
4. Run `./test.sh && ./test-init-switch.sh && ./test-full.sh` — all three must pass
5. Open a PR against `main`
### PR requirements
- Build must pass: `cmake --build build` with zero warnings on Clang 17+
- Tests must pass: all three shell test suites
- Follow the conventions in [STYLEGUIDE.md](STYLEGUIDE.md)
- No commented-out code. No dead code. No TODO without a date.
- Commit messages in imperative: `Add runit backend` not `Added runit backend`
## What we won't merge
- **`systemd`-only features.** If it can't work on at least two init systems,
it goes in a `systemd` package definition, not in kappa.
- **Dependency on a specific distro.** Kappa runs on any Linux kernel. No
hardcoded paths to `/usr/lib/systemd`, no assumptions about `/etc/os-release`.
- **Abstract nonsense.** FactoryFactoryBuilder patterns. Premature
generalization. If you need three layers of indirection to add a feature,
the feature is too complicated.
- **AI slop.** If it looks like ChatGPT wrote it, it gets rejected. We can
tell. Write code like a human who's been doing this for a decade.
## Communication
We don't have a Discord. We don't have a forum. Open an issue. Write a
clear title, a reproduction case, and what you expected. We'll respond
when we respond.
If you want to propose a major feature, open an issue first. Surprise PRs
that rewrite half the codebase get closed without review.
---
Kappa is 0.1.0. Everything is subject to change except the rules above.