Imported from the-hcma/bunnify (
AGENTS.md). Install upstream withnpx skills add the-hcma/bunnify. Copyright stays with the author.
AGENTS.md — Ground Rules for bunnify
This file defines the non-negotiable standards for all contributors (human or AI) working on this codebase. Every change must comply with these rules before it is considered complete.
Session Startup & Cleanup
- At the start of every agent session, before acting from assumed conventions, read this
AGENTS.mdin full, then read everyalwaysApply: truerule under.agents/rules/*.md(plus any whoseglobsmatch files you will touch) —AGENTS.mdand.agents/rules/together are the contract (.cursor/rules/*.mdcare Cursor injection shims only).CLAUDE.md(a@AGENTS.mdimport),.github/copilot-instructions.mdand.github/instructions/agents-rules.instructions.mdare thin shims so Claude Code and Copilot reach the same guidance. - Markdown files you commit, this one included, use one physical line per paragraph, list item and blockquote, with no hard line breaks (see
.agents/rules/github-content-formatting.md). - Mandatory Action: At the beginning of every session (before starting any task), run
~/work/ai/repository-helpers/scripts/dev/start-developmentfrom repository-helpers. - This script cleans up merged worktrees, prunes stale metadata, and syncs via the stacking backend in
.github/stacking-tool(gh-stack—gh stack sync/ rebase as needed). - By default it prompts for a new stack name and creates a new worktree under
.worktrees/<stack-name>-wtready for work. - Non-interactive alternative: bypass the prompt by passing a worktree name:
~/work/ai/repository-helpers/scripts/dev/start-development --worktree <stack-name> --no-interactive - Pass
--resumeto instead pick up an existing in-progress worktree: it lists pending worktrees and lets you select one (or creates a new one if none exist). - After
start-developmentfinishes,cdinto the stack worktree (.worktrees/<stack-name>-wt) before any other work. Do not stay in the primary clone.
Main worktree is off-limits (agents)
The primary clone (repo root — first entry in git worktree list, usually on branch main) is the main worktree. Treat it as read-only unless the user explicitly authorizes touching it in the current conversation.
Never on the main worktree (without explicit user authorization):
- Edit, create, or delete source files, config, or lockfiles
- Run
uv sync, tests, builds, or formatters - Run
dep-updaterwith--dirpointing at the primary clone (it may fast-forwardmainand mutate git state) - Run
gh stack …, commits, checkouts, or other git write operations - Leave uncommitted changes, stray branches, or detached HEAD state
Always do implementation, investigation that mutates state, and validation in a stack worktree under .worktrees/<stack-name>-wt. Pass that path to tools (--dir, cd, etc.).
start-development may update the main worktree for environment sync only; that is not permission to work there. If you need to inspect main without changing it, use read-only commands (git log, git show, gh pr view) or a detached temporary worktree — not the primary clone.
Language & Runtime
- Target Python 3.14+ and Django 6.0+. No deprecated APIs.
- Use
uvas the project dependency manager and runner. - Rely on modern Python features and type hinting whenever possible.
- Remote timeouts and bounded retries:
.cursor/rules/remote-timeouts-retries.mdc(alwaysApply, org rule — template sync repository-helpers#570). Everyurllib.requestcall passestimeout=(reuseDEFAULT_TIMEOUT_SECONDS/PYPI_TIMEOUT_S); any retry is capped/budgeted, backed off, transient-only (never blanketHTTPError), and never re-sends a non-idempotent write.
Formatting & Linting
- Lint + format: We use Ruff (
[tool.ruff]inpyproject.toml). Runuv run ruff check .anduv run ruff format .(or--checkin CI). Ruff replaces black/isort — it does not replace type checking. - Type checking: We use pyright in basic mode for static analysis, configured in
pyproject.toml.- The web framework has dynamic attributes, so certain pyright rules (e.g.,
reportAttributeAccessIssue,reportOptionalMemberAccess) are disabled to avoid false positives. - Run
uv run pyrightand ensure there are zero errors before submitting a PR.
- The web framework has dynamic attributes, so certain pyright rules (e.g.,
- Keep the codebase clean and descriptive.
Testing
- The project relies on built-in unit test suites.
- Use
./test_bunnifyto run all tests. - For targeting specific tests, you can append the test module or class:
./test_bunnify bookmarks.tests.SmokeTests - All new functionality should include relevant test coverage.
- Code must not be merged if
./test_bunnifyfails.
Repository
- Remote:
https://github.com/thehcma/bunnify.git - Never commit secrets, credentials, or API keys.
Commits, Stacking & Pull Requests
- Stacking backend is
gh-stack(see.github/stacking-tool). Do not use Graphite (gt) on this repo. - Full non-interactive reference: gh-stack skill (or
${REPOSITORY_HELPERS_DIR:-$HOME/work/ai/repository-helpers}/.cursor/skills/gh-stack/SKILL.md). - Worktree-per-Stack: Every new stack/PR must be created in its own Git worktree. Use
~/work/ai/repository-helpers/scripts/dev/start-developmentfrom repository-helpers — it creates the worktree and is marker-aware forgh-stack. - Never work directly on
main. Create layers withgh stack init <branch>/gh stack add <branch>, thengit add/git commitas usual. - Prefer
scripts/dev/submit-stackfrom repository-helpers (runs pre-pr checks, thengh stack submit --auto --open). Agents must always pass--auto(and prefer--open) — never interactivegh stack submit/gh stack viewwithout--json. - Merge path is GitHub’s merge queue: enable auto-merge with
gh pr merge --auto --squashwhen the operator asks to merge. Do not use the leftovermerge-itlabel. Always ask the user before enabling auto-merge. - Follow Conventional Commits:
feat:,fix:,chore:,docs:,test:,refactor:. - Keep commits focused. One logical change per commit.
- Always run the full local pre-PR checklist (see below) before submitting. Do not rely on CI to catch issues that can be caught locally.
Shell Scripts
- Do not use
.shextensions for shell script files. shellcheckis required for all shell scripts (localscripts/checksand CI both fail if it is missing or reports issues).- Non-exported variables must be lowercase; only exported environment variables should be UPPERCASE.
- Use
localfor all function-scoped variables in bash scripts and preferreadonlyfor values that must not change. - Prefer long, verbose command-line arguments (e.g.
curl --silentovercurl -s) when composing shell scripts, as they are intrinsically self-documenting. - Always add explicit timeouts for network or long-running external commands: use
curl --max-time <s>for HTTP requests andtimeout <s>for commands that may hang. - When writing server scripts that accept a
--portargument, support0as a valid value to let the OS choose an ephemeral port (useful for tests and CI).
Dependencies
- All dependencies are managed via
uvinpyproject.toml. - Separate runtime dependencies from
dependency-groups.devcorrectly. - Run
uv syncto install/update the environment. - Do not pull in dependencies for functionality that can be trivially recreated using standard Python or built-in framework features natively.
Dependency release age (dep-updater 9 days, Dependabot 10 days)
New dependency versions are adopted on a staggered schedule so dep-updater (repository-helpers) lands updates before Dependabot (aligned with repository-helpers AGENTS.md). This repo has no npm/pnpm frontend; policy applies to pip and GitHub Actions only.
| Layer | Mechanism |
|---|---|
| dep-updater | 9-day gate for Python/PyPI and GitHub Actions bumps (scripts/dep-updater from repository-helpers). |
| Dependabot | Weekly scan + cooldown: default-days: 10 on version-update PRs in .github/dependabot.yml (pip and github-actions; one day after dep-updater). Do not set open-pull-requests-limit: 0 — version updates stay enabled as a backup. |
Dependabot: version bumps vs security
- Version updates — Dependabot checks on the weekly schedule; each proposed bump must pass the 10-day cooldown (release age). dep-updater usually lands the same bump first (9-day gate); Dependabot version PRs after that are redundant and can be closed.
- Security updates — not subject to the version-update cooldown. Dependabot may open a security PR as soon as GitHub has an alert and a fix; merge these promptly.
- dep-updater CVE bypass — when pip-audit reports CVE IDs with an available fix, dep-updater skips the 9-day gate for that package; otherwise use the audit-driven security path (
py_security_update). - CI:
pip-audit(or equivalent) remains the source of truth for known CVEs on runtime deps.
Day-to-day: merge dep-updater batch PRs for routine bumps; close duplicate Dependabot version PRs when dep-updater already has the change (no pnpm grandfathering in this repo).
CI Checks / Pre-PR (all must pass)
uv run ruff check .
uv run ruff format --check .
uv run pyright --warnings
./test_bunnify
No PR may be merged if the above commands fail.
Pre-PR Local Checklist (recommended)
- Run the unified preflight script: Prefer using
scripts/checkswhich runs formatting, linters, unit tests and (optionally) integration tests with sensible timeouts. - Formatting & linting:
uv run ruff check .,uv run ruff format --check ., anduv run pyright --warningsmust pass locally before creating a PR. - Shell linting:
shellcheckmust be installed locally.scripts/checksruns.github/ci/shellcheck(same targets as CI) and fails if shellcheck is missing. - Unit tests: Run
./test_bunnifyand ensure all tests pass. - Integration tests (required pre-PR): Run
./test_integration— this script uses OS-chosen ephemeral ports when passed--port 0and includes explicit timeouts; run it locally to validate end-to-end behavior. - Parallelization guidance: When possible, run formatting and static checks in parallel to reduce feedback time (our CI runs
ruff check,ruff format --check, andpyrightin a separate job from shellcheck and tests). Locally,scripts/checkscan be used as a single-entrypoint; CI runs jobs in parallel automatically.
If any of the above fail locally, fix the issues before opening a PR. The CI will re-run these checks in parallel and block merges on failures.
