Skip to main content

Git Guidelines

Commit messages

This repo follows Conventional Commits: type(scope): summary, imperative mood, present tense. Real examples from the history:

fix(plugins): ignore dotfiles in setup/guardrails, fix 2 stale comments
refactor(microsoft365): retrofit to the new connector/+mcp_bridge/+tests/ layout
docs(plugins): rewrite plugins/README.md for the new folder/manifest layout
test(plugins): widen the sys.modules eviction guard to cover backend/tests/ too
feat(plugins): auto-install plugin_depends recursively, never auto-enable

Common types: feat, fix, refactor, test, docs, chore. The scope is usually a package or capa name (capas, microsoft365, frontend) — pick whatever names the part of the codebase the commit actually touches.

The summary line explains why, not just what changed — "fix(plugins): ignore dotfiles in setup/guardrails" tells a reader what broke without them opening the diff; "fix(plugins): update discovery.py" doesn't. For a commit whose reasoning isn't obvious from the summary alone, use the commit body to explain the reasoning, not to restate the diff.

Atomic commits

One logical change per commit. A commit that mixes an unrelated reformatting pass with a real fix makes the fix harder to review and git bisect less useful later. If you're tempted to write "and also" in a commit message, it's probably two commits.

Before opening a pull request

cd backend
uv run ruff check src tests
uv run ruff format --check src tests
uv run mypy
uv run pytest

A PR that doesn't pass this locally won't pass CI either — running it first saves a review round-trip.

Never rewrite published history on a shared branch

Don't force-push, rebase, or amend a commit that's already been pushed to a branch other people build on. If a commit needs fixing after the fact, add a new commit that fixes it, rather than rewriting the one that's wrong.

Next