Kia ora! Thank you for joining our mission to accelerate conservation through AI.
Whether you're here to squash (software) bugs, improve documentation, or build new features, we just ask that you follow our Wildlines below.
Thanks for helping us keep the world wild!🦤🦎🐅🌳🐠
- Core Principles
- Branching Strategy
- Standard Workflow
- Switching Tasks (Staggered Development)
- Post-Merge Cleanup
- Repository Protections (Admins Only)
- Quick Reference Cheat-sheet
- AI Usage and Agents
- Linear History: We rebase; we don't merge bubbles.
- Review Everything: No code lands in
devwithout a second pair of eyes (Gemini + Human). - Default to
dev:mainis for stable releases only.
gitGraph
commit id: "release"
branch dev
checkout dev
commit id: "integration"
branch feature/task-a
checkout feature/task-a
commit id: "feat: task a"
checkout dev
branch feature/task-b
checkout feature/task-b
commit id: "fix: task b"
checkout dev
merge feature/task-a
merge feature/task-b
checkout main
merge dev id: "v1.2.0"
| Branch | Purpose | Direct commits? |
|---|---|---|
main |
Stable production releases | Never — only merged from dev via PR |
dev |
Integration branch — the base for all work | Never — only merged from feature branches via PR |
feature/* |
Individual task, fix, or experiment | Yes |
Important
All work starts and ends with dev. Never commit directly to dev or main.
Use a short, descriptive name with one of the following prefixes:
| Prefix | Use for |
|---|---|
feature/ |
New functionality (e.g. feature/add-lora-retry) |
fix/ |
Bug fixes (e.g. fix/ble-timeout) |
docs/ |
Documentation only (e.g. docs/update-contributing) |
chore/ |
Maintenance, deps, config (e.g. chore/update-deps) |
refactor/ |
Code restructure with no behaviour change |
Stacked branches — use a sequence number. If you are building a chain of dependent branches, add a two-digit sequence number so the order is always unambiguous, both to you and to reviewers:
feature/01-ble-init
feature/02-ble-send
feature/03-ble-retry
This makes it immediately clear which branch depends on which, and prevents confusion when multiple PRs are open at the same time.
Tip
Before starting any git work, copy the team's git skill to your machine (see Section 8.1) and load it into your AI coding tool (see Section 8.2). It encodes every rule in this section as a strict, agent-readable reference.
Always branch from the latest dev to ensure you are building on the most recent work:
git checkout dev
git fetch origin --prune && git rebase origin/dev
git checkout -b feature/your-descriptive-nameMake small, focused commits as you work. We use Conventional Commits to help automate release notes.
Format: <type>: <short description>
git add -A
git commit -m "fix: add retry logic for BLE command timeout"Common types: feat, fix, docs, chore, refactor, test
Write commit messages that explain what changed and why, not just what the code does.
Warning
Commit Body Length: Ensure that any extended description (the body) of your commit messages hard-wraps at 100 characters maximum per line. If a single line in the body exceeds 100 characters, the commitlint CI check will fail.
Tip
Commit signing: If your repo requires signed commits, ensure it's configured:
git config commit.gpgsign trueBefore you push (or create a PR), rebase your branch onto the latest dev to keep a linear history and avoid messy "merge bubbles."
git fetch origin
git rebase origin/devIf there are conflicts, Git will pause and let you resolve them file by file:
# After resolving each conflict:
git add <resolved-file>
git rebase --continue
# To abort and return to your previous state:
git rebase --abortTip
Why rebase instead of merge? Rebasing rewrites your commits on top of the latest dev, so your work appears sequentially after the latest changes — producing a clean, readable history with no merge commits.
If this branch has never been pushed to GitHub before, Git doesn't yet know where to send it. You must set the upstream remote the first time:
# First push — sets the upstream tracking branch on GitHub
git push --set-upstream origin feature/your-descriptive-name
# Shorthand: git push -u origin feature/your-descriptive-nameAfter that first push, Git remembers the link. For all subsequent pushes (including after a rebase):
# Subsequent pushes (branch already exists on GitHub)
git push origin feature/your-descriptive-name
# After a rebase (branch already exists on GitHub)
git push --force-with-lease origin feature/your-descriptive-nameWarning
Always use --force-with-lease instead of --force when overwriting remote history. It checks that nobody else has pushed to the branch since your last fetch, preventing you from accidentally overwriting their work.
Important
Stacked branches: If this branch was created from another feature branch (Option B in the Staggered Development section), set the base to that parent feature branch — not dev. Setting it to dev by mistake will include all of the parent branch's uncommitted changes in your PR diff, which is not what you want. You will update the base to dev only after the parent branch merges.
- Go to the repository on GitHub and click "New pull request".
- Set the branches:
- base:
dev(or your parent feature branch if this is a stacked branch — see note above) - compare:
feature/your-descriptive-name(your branch)
- base:
- Fill in the PR description. At minimum, include:
- What was changed and why
- How to test the change
- Screenshots (if there is a UI impact)
- Links to any related issues or tasks
- Add a human reviewer straight away (e.g. Tobyn or Kalindi) — you don't need to wait for Gemini to finish first. They'll review once Gemini's pass is complete, so adding them early means no delay.
- If your work is still in progress, open it as a Draft PR to signal it's not ready for review yet. Switch it to "Ready for review" when done.
Tip
You can create a draft PR from the GitHub UI (click the arrow next to "Create pull request" → "Create draft pull request") or via the CLI:
gh pr create --draftNo code lands without review. The process has two stages:
Stage 1 — Automated Review (Gemini)
When you open or update a PR, Gemini (an AI code review tool) will automatically analyse your changes. You must address every comment — either fix the code or reply with a clear justification for why you haven't.
To push fixes in response to Gemini's comments, simply commit and push to the same branch as normal:
git add -A && git commit -m "fix: address Gemini review comments"
git push origin feature/your-descriptive-nameNote
You don't need to do anything else. Pushing new commits to the branch automatically updates the open PR and triggers Gemini to re-run its review. You do not need to update the PR manually, close it, or open a new one.
Stage 2 — Human Review
Your human reviewer (added when you created the PR) will be notified once Gemini's review is satisfied. They will check for correctness, readability, and architecture alignment. If they request changes, push fixes the same way as above — the PR updates automatically.
Merge
Once approved, the reviewer or PR author merges the PR into dev.
If you finish a task, open a PR, and want to keep working without waiting for review, you have two options depending on whether your new task relies on the un-merged work.
If your new task is completely unrelated to the open PR, branch fresh from dev:
git add -A && git commit -m "feat: finish task 1"
git checkout dev
git pull origin dev
git checkout -b feature/independent-taskIf your new task depends on the open PR, branch directly from your current feature branch instead of dev:
# 1. Ensure you are on the completed, un-merged branch
git checkout feature/task-1-fix
# 2. Create a new branch from it
git checkout -b feature/task-2-new-feature
# 3. Work, commit, and push normally
git add -A && git commit -m "feat: add new feature based on task 1 fix"
git push origin feature/task-2-new-featureHow the stacked PR setup looks:
dev
└── feature/task-1-fix ← PR #1 targets dev
└── feature/task-2-new-feature ← PR #2 targets feature/task-1-fix
Once PR #1 merges into dev:
- Edit your
task-2PR on GitHub and change the base branch back todev. - Rebase
task-2locally onto the updateddevand force-push:
git checkout feature/task-2-new-feature
git fetch origin
git rebase origin/dev
git push --force-with-lease origin feature/task-2-new-featureAfter the rebase, the history looks like:
dev
└── feature/task-2-new-feature ← PR #2 now targets dev directly
Once your PR is merged, delete your feature branch to keep the repo tidy:
git checkout dev
git pull origin dev
git branch -d feature/your-descriptive-nameNote
If Git refuses to delete the branch (common after a squash merge, since the commit hashes differ), use -D to force-delete:
git branch -D feature/your-descriptive-nameYou can also delete the remote branch directly from the GitHub PR page after merging.
If you have been working with a chain of stacked branches (e.g. feature/01-ble-init → feature/02-ble-send → feature/03-ble-retry), merges cascade one at a time. Here is what to do each time a branch in the chain merges:
After feature/01-ble-init merges into dev:
- Update your local
dev:git checkout dev && git pull origin dev - On GitHub, edit the PR for
feature/02-ble-sendand change its base branch fromfeature/01-ble-init→dev. - Rebase
02onto the updateddevand force-push:git checkout feature/02-ble-send git rebase origin/dev git push --force-with-lease origin feature/02-ble-send
- Delete the now-merged branch locally:
git branch -D feature/01-ble-init
Repeat this process each time the next branch in the chain merges. After each merge the next branch in line becomes a direct child of dev, and the sequence number in the name makes it easy to track where you are in the chain.
Tip
Check which branches you still have locally at any time with:
git branch -vvBranches marked [origin/...: gone] have had their remote deleted and are safe to remove.
All Wildlife.ai repos should have the following settings configured in GitHub under Settings → Branches:
- Default Branch: Set to
dev. - Protection Rules for both
mainanddev:- Require a pull request before merging
- Require at least 1 approval
- Dismiss stale reviews when new commits are pushed
- Restrict direct pushes — no one should bypass PRs for these branches
main ← (release PRs only)
↑
dev ← (all feature PRs target here)
/ | \
feature/ feature/ feature/
task-a task-b task-c
# ── Start ───────────────────────────────────────────────
git checkout dev && git pull origin dev
git checkout -b feature/my-task
# ── Commit ──────────────────────────────────────────────
git add -A && git commit -m "feat: describe what you did"
# ── Rebase & Push ───────────────────────────────────────
git fetch origin && git rebase origin/dev
git push origin feature/my-task # first push
git push --force-with-lease origin feature/my-task # after rebase
# ── Open PR (draft while WIP) ───────────────────────────
gh pr create --draft
# ── Cleanup after merge ─────────────────────────────────
git checkout dev && git pull origin dev
git branch -d feature/my-task # use -D if squash-mergedWe use AI tools to accelerate development, but all outputs must remain maintainable, portable, and aligned with our engineering standards.
- Keep the Codebase Clean and Intentional
- Commit only code and documentation that is reviewed, understood, and necessary
- Avoid large or duplicated AI-generated documentation
- Use Standardised Structures
- Store documentation, agent definitions, and reusable skills in structured locations (e.g. /docs/, /agents/, /skills/)
- Use tool-agnostic formats (Markdown, JSON and YAML)
- Document patterns, decisions, and reusable approaches rather than raw outputs
- Promote Reuse and Avoid Duplication
- Reuse existing patterns, prompts, and components before creating new ones
- Consolidate shared logic and knowledge to prevent parallel or duplicated solutions
- Keep workflows and outputs portable, so any team member or tool can build on them
The team maintains a single source-of-truth skill file at: /agents/git-SKILL.md
Copy it to your machine once per project clone:
# from the repo root
mkdir -p ~/.config/wildlife-ai && cp agents/git-SKILL.md ~/.config/wildlife-ai/git-SKILL.mdOr keep it in the repo root and reference it by relative path — either works as long as your tool can read it (see Section 8.2).
Important
If the skill file is updated in dev, pull the latest and re-copy.
An outdated local copy will drift from the team's actual rules.
Important
Ensure you have the GitHub CLI (gh) installed and authenticated (gh auth login), as the skill relies heavily on it.
Load the skill so your agent follows it automatically on every git operation. Pick the setup for your tool below — you only need to do this once per project.
Create or edit CLAUDE.md in the repo root:
## Git workflow
Before any git operation, read and strictly follow `~/.config/wildlife-ai/git-SKILL.md`.
Never perform a git action that contradicts a rule in that file.Claude Code reads CLAUDE.md automatically at session start.
Create or edit .cursor/rules/git.mdc in the repo root:
description: Enforces Wildlife.ai git workflow rules for any git operation globs: ["**/*"] alwaysApply: true
Before any git operation (branch, commit, push, PR, rebase, cleanup), read and strictly follow ~/.config/wildlife-ai/git-SKILL.md. Never perform a git action that contradicts a rule in that file.
Create or edit .github/copilot-instructions.md:
## Git workflow
Before any git operation, read and strictly follow `~/.config/wildlife-ai/git-SKILL.md`.
Never perform a git action that contradicts a rule in that file.Add the following to your tool's system prompt, project instructions, or equivalent config file: Before any git operation, read and strictly follow ~/.config/wildlife-ai/git-SKILL.md. Never perform a git action that contradicts a rule in that file.
Note
The skill file is intentionally short (~1,200 tokens) so it can be loaded into context on every session without meaningful cost. If your tool has a context limit, prefer the skill file over any inline git instructions — the skill is the authoritative source.
Questions? Reach out or post in the team's Slack.
Ngā mihi nui (thanks a lot) for your contribution! 🙏