Thanks for your interest in contributing to OpSentry.
Open a GitHub issue with:
- What you expected to happen
- What actually happened
- Steps to reproduce
- Your OS and shell (bash/zsh)
If you find a dangerous pattern that OpSentry should block, open an issue with:
- The pattern (command, file path, or code snippet)
- Why it should be blocked
- Which hook script should handle it
- Fork the repo
- Create a feature branch off
develop(git checkout -b feature/block-new-pattern develop) - Make your changes
- Run the test suite:
./test.sh - Ensure all 88+ tests pass
- Bump
VERSION, add aCHANGELOG.mdentry, and update the docs (see below) - Submit a PR against
develop
| Branch | Role |
|---|---|
main |
Production. Only ever updated by merging release/* or hotfix/*. |
develop |
Integration branch. Default target for PRs. |
feature/<name> |
Branched from develop, merged back into develop. |
bugfix/<name> |
Non-urgent fixes. Branched from develop. |
release/<version> |
Cut from develop, merged into main and back into develop. |
hotfix/<version> |
Cut from main for urgent fixes, merged into main and develop. |
Never commit directly to main or develop.
Semantic Versioning (MAJOR.MINOR.PATCH), tracked in the VERSION file at the repo root.
- MAJOR — breaking changes to hook behavior, exit codes, or the installed config surface
- MINOR — new hooks, new blocked patterns, backwards-compatible additions
- PATCH — bug fixes, false-positive corrections, documentation, refactors
Every commit bumps VERSION and stages it alongside the change. Releases that land on
main are tagged v<version>.
A change is not complete until all four land in the same commit:
- Code — the change itself, with tests in
test.sh VERSION— bumped per SemVerCHANGELOG.md— entry under## [Unreleased], in the appropriate### Added/### Changed/### Deprecated/### Removed/### Fixed/### Securitysubsection- Docs —
README.mdfor any new or changed hook,docs/quickstart.mdfor anything affecting installation or first-run behavior, and migration notes for breaking changes
If a change genuinely affects no documentation, say so in the PR rather than skipping silently.
Conventional Commits, with the resulting version in brackets:
type(scope): subject [vX.Y.Z]
type is one of feat, fix, docs, style, refactor, perf, test, chore,
build, ci. Subject is imperative and under 72 characters. Use the body to explain
why, not what.
Examples:
feat(hooks): block dlopen with variable paths [v1.9.0]fix(block-scope-escape): stop false-positive on ~/Library [v1.8.2]
- Cut
release/<version>fromdevelop - Roll
## [Unreleased]into a## [<version>] - <YYYY-MM-DD>section - Open a PR into
main, merge, then tagv<version> - Merge
mainback intodevelop - Delete the release branch locally and on the remote, and close any PRs the release supersedes
- Hook scripts use
set -euo pipefail - Use
jqfor JSON parsing in hooks - Exit code
0= allow, exit code2= block - Blocked messages go to stderr
- Every hook must log blocks to
~/.claude/guardrail-blocks.log
- Create the script in
opsentry/claude/hooks/ - Follow the existing pattern: parse JSON stdin, check patterns, exit 0 or 2
- Add the
log_blockfunction for incident logging - Add tests to
test.sh - Document the hook in
README.md
Be respectful, constructive, and professional. We are building security tooling — precision and clarity matter more than speed.
By contributing, you agree that your contributions will be licensed under the Apache License 2.0.