Thanks for your interest in contributing to Aegis! Here's how to get started.
-
Clone the repo
git clone https://github.com/edycutjong/aegis.git cd aegis -
Backend
cd backend python -m venv venv && source venv/bin/activate pip install -r requirements-dev.txt cp .env.example .env # Fill in your API keys
-
Frontend
cd frontend npm install -
Run everything
docker compose up --build
# Backend (100% coverage required)
cd backend
python -m pytest tests/ --cov=app --cov-fail-under=100
# Frontend
cd frontend
npm run test
npx vitest run --coverage- Backend: Code is linted with Ruff. Run
ruff check .before committing. - Frontend: Code is linted with ESLint. Run
npm run lintbefore committing.
- Fork the repository and create a feature branch from
main - Make your changes with clear, descriptive commits
- Ensure all tests pass and coverage remains at 100%
- Run linting (
ruff check .andnpm run lint) - Open a PR with a clear description of the changes
Open an issue with:
- A clear title and description
- Steps to reproduce (if applicable)
- Expected vs actual behavior
- Screenshots or logs (if helpful)
By contributing, you agree that your contributions will be licensed under the MIT License.
Name regression tests after the defect they pin, not after the code path:
# opaque — proves nothing to a reader
def test_model_router_3(): ...
# the test list becomes a changelog of real bugs found and fixed
def test_openai_namespaced_model_routes_to_groq_not_openai(): ...
def test_reactivate_requires_human_approval(): ...Anyone skimming tests/ should be able to see that development was iterative
rather than a single scaffold.
Safety invariants live in backend/tests/test_safety_invariants.py. It
verifies the HITL approval gate and the table allowlist exhaustively across
their whole input space, and asserts the combination counts. If you change an
action type or an approval status, that assertion fails on purpose — update the
count and the number quoted in README.md in the same commit.
Backend coverage is gated at 100% (--cov-fail-under=100) and frontend
coverage is gated via vitest.config.ts thresholds. Both must stay green.