AI Assistant Instructions¶
BumpCalver ships app-integration guidance for AI assistants as package
data — the same guidance an assistant would otherwise have to
reverse-engineer from this documentation site, bundled directly with the
version of bumpcalver you actually installed, so it can never drift out of
sync with an externally copy-pasted snippet.
This isn't guidance for using bumpcalver's own source code — it's guidance
for an assistant helping a developer configure bumpcalver in their own
project: authoring the [tool.bumpcalver] config block, picking the right
file_type for each version-carrying file, and choosing one of the three
versioning modes.
Quick start¶
python -m bumpcalver.ai_instructions claude --write # writes ./CLAUDE.md
python -m bumpcalver.ai_instructions copilot --write # writes ./.github/copilot-instructions.md
python -m bumpcalver.ai_instructions generic > AI_INSTRUCTIONS.md
Or in-process:
from bumpcalver import (
available_instruction_profiles,
get_app_instructions,
suggested_instruction_filename,
)
print(available_instruction_profiles()) # ('claude', 'copilot', 'generic')
print(get_app_instructions("claude"))
print(suggested_instruction_filename("claude")) # "CLAUDE.md"
Aliases are accepted: github-copilot → copilot, anthropic-claude →
claude, default → generic.
See API Reference for the full
get_app_instructions/available_instruction_profiles/
suggested_instruction_filename signatures.
CLI¶
usage: python -m bumpcalver.ai_instructions [-h] [--write] [--output PATH]
[profile]
profile— one ofclaude/copilot/generic(or an alias); defaults togeneric.--write— write to the profile's suggested destination file (CLAUDE.md,.github/copilot-instructions.md, orAI_INSTRUCTIONS.md) instead of stdout.--output PATH— write to an explicit path instead.PATHis validated to stay within the current working directory (see "Security" below) — this matters because the whole point of this CLI is that an AI assistant may invoke it directly, not just a human typing a path by hand.
Full instructions by profile¶
The three sections below are the exact, literal content of the packaged
instruction files, generated into this page at build time from the same
get_app_instructions() the CLI and Python API serve — not a manually
copied snapshot that could drift out of sync with what
python -m bumpcalver.ai_instructions <profile> actually outputs.
Generic¶
# Generic AI assistant instructions for apps using bumpcalver
Goal: correctly configure `bumpcalver` in an application repository —
authoring its `[tool.bumpcalver]` config and choosing the right CLI
invocation — without reverse-engineering the library's internals.
`bumpcalver` is a CLI/config-driven tool, not a library your code imports
and calls. "Integration" here means: get the config block right, pick the
correct `file_type` for every file that carries a version string, and pick
exactly one versioning mode.
## Setup: from zero to a working config
Follow this order — skipping steps (especially the "seed an initial version"
step) is the most common way a first setup silently does nothing.
### 1. Install
```bash
pip install bumpcalver
# or add "bumpcalver" to the project's dev dependencies
```
### 2. Decide where the config lives
- **If the project already has a `pyproject.toml`** (almost always true for
a Python package): add a `[tool.bumpcalver]` table to it. This is the
default choice.
- **If there is no `pyproject.toml`**, or the project's owner wants
bumpcalver config kept separate: create a standalone `bumpcalver.toml` in
the project root instead.
- If **both** exist in the same directory, bumpcalver uses `pyproject.toml`
and ignores `bumpcalver.toml` — never create both and expect the second
one to matter.
⚠️ **The two files use different key nesting — this is a real, easy-to-miss
trap:**
| In `pyproject.toml` | In standalone `bumpcalver.toml` |
|---|---|
| `[tool.bumpcalver]` table | keys at the **top level** of the file |
| `[[tool.bumpcalver.file]]` | `[[file]]` |
Writing `[[tool.bumpcalver.file]]` inside a standalone `bumpcalver.toml`
does not error — it just silently produces an empty file list, because
`bumpcalver.toml` is parsed flat (no `tool.bumpcalver` nesting expected). If
nothing gets updated after a `--build`, check this first.
### 3. Seed an initial version string in every target file
**bumpcalver finds and replaces an existing version string — it does not
create files or insert a new key.** Before writing any config, make sure
every file you intend to list already contains a literal version value in
the right shape, e.g.:
- Python: `__version__ = "2024.01.01"`
- TOML (`pyproject.toml` itself): `version = "2024.01.01"` under `[project]`
- JSON: `"version": "2024.01.01"` as a top-level key
- Dockerfile: `ARG VERSION=2024.01.01` and/or `ENV APP_VERSION=2024.01.01`
If a file is missing the key entirely, bumpcalver's update for that file
will fail (prints a "not found" message, doesn't write, doesn't error the
whole run) — that's a config/file mismatch to fix, not something bumpcalver
will fix for you.
### 4. Identify every file that needs updating, and map each to the table below
Walk the repo (or ask the user) for every file that carries this project's
version: the package's own version attribute, `pyproject.toml`'s
`project.version`, a Dockerfile `ARG`/`ENV`, a `package.json`-style file, a
docs page, etc. For each one, look up `file_type` in the table in the next
section and write one `[[tool.bumpcalver.file]]` (or `[[file]]`) block.
### 5. Choose `version_format`, `date_format`, `timezone`
If unsure, these are sane, verified defaults:
```toml
version_format = "{current_date}.{build_count:03}"
date_format = "%Y.%m.%d"
timezone = "America/New_York"
```
(`{current_date}` uses whatever `date_format` you set; `{build_count:03}`
zero-pads to 3 digits and only applies with `--build` — see "Versioning
modes" below for the full placeholder set including hybrid semver.)
### 6. Decide `git_tag` / `auto_commit`, and set them explicitly
Default to `false` for both unless the user explicitly asked for git
automation — see "Security / side-effect contract" below for why.
### 7. Add the `.gitignore` entries (see the dedicated section below)
### 8. Verify before the first real run
Always run `bumpcalver --dry-run` (add `--build` too if using build-count or
hybrid mode) immediately after writing the config, **before** running it for
real. It prints exactly what would change without writing anything:
```
[dry-run] Would bump version to 2024.01.02.001 in:
[dry-run] src/mypkg/__init__.py
[dry-run] pyproject.toml
```
If instead it prints `No files specified in the configuration.`, the config
wasn't found or parsed — check step 2's nesting trap first. If a file you
expected is missing from the list, check step 3 (the file's current content
doesn't match `variable`/`pattern`).
### Minimal working example (single file)
```toml
[tool.bumpcalver]
version_format = "{current_date}.{build_count:03}"
date_format = "%Y.%m.%d"
timezone = "America/New_York"
git_tag = false
auto_commit = false
[[tool.bumpcalver.file]]
path = "src/mypkg/__init__.py"
file_type = "python"
variable = "__version__"
```
### Typical Python package (multiple files, the common real-world case)
```toml
[tool.bumpcalver]
version_format = "{current_date}.{build_count:03}"
date_format = "%Y.%m.%d"
timezone = "America/New_York"
git_tag = true
auto_commit = false
[[tool.bumpcalver.file]]
path = "pyproject.toml"
file_type = "toml"
variable = "project.version"
version_standard = "python"
[[tool.bumpcalver.file]]
path = "src/mypkg/__init__.py"
file_type = "python"
variable = "__version__"
version_standard = "python"
```
Run `bumpcalver --build --dry-run` against this, confirm the preview looks
right, then drop `--dry-run` to apply it for real.
## Completion contract (always deliver all items)
1. A `[tool.bumpcalver]` table in `pyproject.toml` (or a standalone
`bumpcalver.toml`) with `version_format`, `date_format`, and `timezone`.
2. One `[[tool.bumpcalver.file]]` block **per file that carries a version
string**, with the correct `file_type` and the matching
`variable`/`directive`/`pattern` for that format (see the table below —
these are not interchangeable).
3. Exactly one versioning mode, chosen deliberately (see "Versioning modes").
4. If pre-release suffixes (`--beta`/`--rc`/`--release`/`--custom`) are
needed, the corresponding `beta_format`/`rc_format`/`release_format` keys.
5. An explicit statement of whether `git_tag`/`auto_commit` are enabled, and
that enabling them causes a **real git commit and tag** — not a preview.
6. `.bumpcalver/` and `bumpcalver-history.json` added to `.gitignore`.
7. A short explanation of any non-obvious `file_type`/`variable` mapping choice.
## Supported file types (as of this bumpcalver version)
| `file_type` | `variable` means | Notes |
|---|---|---|
| `python` | Python variable name, e.g. `__version__` | Regex substitution |
| `toml` | **Dot-separated path**, e.g. `project.version` | Style-preserving (comments/order survive) |
| `yaml` | **Dot-separated path**, e.g. `configuration.version` | Style-preserving (comments/order survive) |
| `json` | **Plain top-level key**, e.g. `version` — NOT a dot path | Nested keys are not supported |
| `xml` | `ElementTree.find()` path, e.g. `version` or `metadata/version` | See XML caveat below |
| `dockerfile` | Variable name | **Requires `directive = "ARG"` or `"ENV"`** |
| `makefile` | Makefile variable name, e.g. `APP_VERSION` | |
| `properties` | `KEY` in a `KEY=value` file | |
| `env` | `KEY` in a `KEY=value` file (`.env`) | Quotes are stripped on read |
| `setup.cfg` | Dot path (`metadata.version`) or a simple key | |
| `text` | Not used — the whole file *is* the version | For a bare `VERSION` file |
| `regex` | Any key name | **Requires `pattern`**: a regex with exactly one capture group around the version |
Third-party file types can be added via the `bumpcalver.handlers` entry-point
group without forking bumpcalver — see the plugin-authoring guide if a
project needs a format not in this table.
**Do not confuse `json`'s plain top-level key with `toml`/`yaml`'s dot path**
— they look similar but are different mechanisms. Using a dot path for a
JSON file's `variable` will silently fail to find the key.
## Versioning modes — pick exactly one
These are different mechanisms, not variations of one setting. Picking the
wrong one silently produces a version scheme the developer didn't ask for.
1. **Plain calendar** (default): `version_format` uses only `{current_date}`.
Every invocation produces a fresh date-based version.
2. **Calendar + build count**: `version_format` includes `{build_count}`
(optionally `{build_count:03}` for zero-padding) and the CLI is invoked
with `--build`. The build count increments only when invoked again on
the same date; a new date resets it to 1.
3. **Hybrid semver + calendar**: `version_format` includes `{major}`,
`{minor}`, and/or `{patch}` alongside `{current_date}`/`{build_count}`,
and the config has integer `major`/`minor`/`patch` keys. Bump the
semantic prefix with `--bump major|minor|patch` (this both increments the
value in config and persists it back to the config file — a real write).
## Constraints vs. cosmetic — do not confuse these
- `version_standard = "python"` on a `[[tool.bumpcalver.file]]` block is
**enforced**: it PEP-440-normalizes the version string before writing it
(e.g. strips leading zeros, converts separators). Any other value (or
omitting the key) is a no-op passthrough.
- **`file_type` is never validated against the file's actual content.**
Nothing stops a config from setting `file_type = "python"` on a Ruby file
— if the regex happens to match `__version__ = "..."`-shaped text it will
"work" by coincidence, not because Ruby is a supported format. For a
non-Python `KEY = "value"`-style file, use `file_type = "regex"` with an
explicit `pattern` instead of borrowing an unrelated handler.
## Known limitation
`xml`'s `update_version` preserves the `<?xml ?>` declaration and comments
nested *inside* the root element, but comments in the XML **prolog** (before
the root element's opening tag) are dropped on write — a structural
`ElementTree` limitation, not a bug. Flag this if a target XML file has
prolog comments worth preserving.
## Security / side-effect contract
- `git_tag = true` and `auto_commit = true` cause `bumpcalver` to create a
**real git tag** (and, with `auto_commit`, a **real commit**) on every
successful run — not a dry-run or a suggestion. State explicitly which of
these are enabled in any configuration you produce.
- `--dry-run` computes and prints what *would* change without writing
anything or touching git — use it to preview a config before committing
to it in CI.
- `--json` emits exactly one JSON object on stdout (log lines move to
stderr) — the machine-readable way to capture the computed version, e.g.
in a CI step: `` bumpcalver --build --json 2>/dev/null | jq -r '.version' ``.
- `--config-file PATH` (or `BUMPCALVER_CONFIG` env var) points at a config
outside the current directory; file paths inside that config resolve
relative to the config file's own directory, not the invoking cwd.
- `--undo`, `--undo-id`, and `--list-history` restore previous state from
`.bumpcalver/backups/` + `bumpcalver-history.json` (both written to the
current working directory). These flags are mutually exclusive with every
version-bump option, including `--dry-run`, `--config-file`, and `--json`.
## `.gitignore` (always add this when configuring bumpcalver in a new repo)
```gitignore
# BumpCalver backup and history files
.bumpcalver/
bumpcalver-history.json
```
## Common mistakes to avoid
- Do not use a dot path for a `json` file's `variable` — it must be a plain
top-level key.
- Do not set `file_type = "dockerfile"` without a `directive` — it's
required, not optional.
- Do not set `file_type = "regex"` without a `pattern` — and the pattern
must have exactly one capture group, or bumpcalver raises an error.
- Do not enable `git_tag`/`auto_commit` in an example/demo config without
saying so explicitly — this is a real, not simulated, side effect.
- Do not combine `--dry-run`/`--config-file`/`--json` with
`--undo`/`--undo-id`/`--list-history` — bumpcalver rejects this combination.
- Do not forget `.bumpcalver/` and `bumpcalver-history.json` in `.gitignore`.
## Prompt starters
"Set up bumpcalver for this Python package: bump `__version__` in
`src/mypkg/__init__.py` and `project.version` in `pyproject.toml` together,
using calendar + build count versioning, no git tagging."
"Add hybrid semver + calendar versioning to this repo: `major`/`minor`
starting at `1.0`, calendar suffix, git tag and commit enabled, and update
both `pyproject.toml` and a Dockerfile's `ARG VERSION`."
Claude¶
# Claude instructions for apps using bumpcalver
You are configuring `bumpcalver`, a CLI/config-driven calendar-versioning
tool, in an application repository. This is not a library you import and
call from app code — the entire integration surface is a `[tool.bumpcalver]`
config block plus the `bumpcalver` CLI invocation. Do not guess the schema;
follow this contract.
## Setup procedure — follow in order
1. **Install**: `pip install bumpcalver` (or add to dev dependencies).
2. **Pick where the config lives**:
- Project already has `pyproject.toml`? Add `[tool.bumpcalver]` to it.
This is the default choice.
- No `pyproject.toml`, or the user wants bumpcalver config separate?
Create a standalone `bumpcalver.toml` in the project root.
- If both exist, bumpcalver reads `pyproject.toml` and ignores
`bumpcalver.toml` entirely — never create both.
- **Nesting differs between the two** and this is a real trap: in
`pyproject.toml` it's `[tool.bumpcalver]` + `[[tool.bumpcalver.file]]`;
in standalone `bumpcalver.toml` it's flat — keys at the top level, and
`[[file]]` (not `[[tool.bumpcalver.file]]`). Using the nested form in a
standalone file doesn't error, it just silently produces an empty file
list.
3. **Confirm every target file already has a version string to replace.**
bumpcalver finds-and-replaces an existing value; it does not create
files or insert a new key. If a file is missing the key, ask the user to
seed one first (e.g. `__version__ = "2024.01.01"`) — don't assume
bumpcalver will add it.
4. **Enumerate every file that carries a version** (package version
attribute, `pyproject.toml`'s own `project.version`, Dockerfile
`ARG`/`ENV`, etc.) and write one `[[tool.bumpcalver.file]]`/`[[file]]`
block per file using the reference table below.
5. **Set `version_format`/`date_format`/`timezone`.** If unsure, use:
`version_format = "{current_date}.{build_count:03}"`,
`date_format = "%Y.%m.%d"`, `timezone = "America/New_York"`.
6. **Set `git_tag`/`auto_commit` explicitly** — default `false` unless the
user asked for git automation (real side effect, see below).
7. **Add the `.gitignore` entries** (below).
8. **Verify with `bumpcalver --dry-run`** (add `--build` if using build
count or hybrid mode) before running for real. It prints exactly what
would change, e.g. `[dry-run] Would bump version to ... in: ...`. If it
prints `No files specified in the configuration.`, re-check step 2's
nesting. If an expected file is missing from the preview, re-check step 3.
### Minimal example
```toml
[tool.bumpcalver]
version_format = "{current_date}.{build_count:03}"
date_format = "%Y.%m.%d"
timezone = "America/New_York"
git_tag = false
auto_commit = false
[[tool.bumpcalver.file]]
path = "src/mypkg/__init__.py"
file_type = "python"
variable = "__version__"
```
### Typical Python package (the common real-world case)
```toml
[tool.bumpcalver]
version_format = "{current_date}.{build_count:03}"
date_format = "%Y.%m.%d"
timezone = "America/New_York"
git_tag = true
auto_commit = false
[[tool.bumpcalver.file]]
path = "pyproject.toml"
file_type = "toml"
variable = "project.version"
version_standard = "python"
[[tool.bumpcalver.file]]
path = "src/mypkg/__init__.py"
file_type = "python"
variable = "__version__"
version_standard = "python"
```
## Completion contract
When asked to configure bumpcalver, deliver all of the following, not a
partial subset:
1. A `[tool.bumpcalver]` table in `pyproject.toml`, or a standalone
`bumpcalver.toml` if the project doesn't want bumpcalver config mixed
into `pyproject.toml` — with `version_format`, `date_format`, `timezone`.
2. One `[[tool.bumpcalver.file]]` block per file that carries a version
string, each with the correct `file_type` for that file's real format
(table below) and the matching `variable`/`directive`/`pattern`.
3. Exactly one versioning mode, chosen deliberately and stated in your
response — see "Versioning modes."
4. `.bumpcalver/` and `bumpcalver-history.json` added to `.gitignore`.
5. If `git_tag`/`auto_commit` are set to `true`, say so explicitly in your
response — these are real git operations, not previewed ones.
## File type reference
| `file_type` | `variable` semantics | Required extra keys |
|---|---|---|
| `python` | Python variable name (`__version__`) | — |
| `toml` | dot path (`project.version`) | — |
| `yaml` | dot path (`configuration.version`) | — |
| `json` | **plain top-level key only** — not a dot path | — |
| `xml` | `ElementTree.find()` path (`version`, `metadata/version`) | — |
| `dockerfile` | variable name | `directive = "ARG"` or `"ENV"` (mandatory) |
| `makefile` | Makefile variable name | — |
| `properties` | `KEY=value` key | — |
| `env` | `.env` `KEY=value` key | — |
| `setup.cfg` | dot path or simple key | — |
| `text` | none — whole file is the version | — |
| `regex` | any name | `pattern` (mandatory, exactly one capture group) |
If a target file's format isn't in this table, do not force-fit
`file_type = "python"` or another close-enough handler onto it just because
its regex happens to match — that's coincidental, not supported, behavior
(see "Enforced vs. coincidental" below). Prefer `file_type = "regex"` with
an explicit `pattern` for `KEY = "value"`-style files (Ruby, Rust, Go,
Java, etc.), or point the user at bumpcalver's `bumpcalver.handlers`
entry-point plugin mechanism if they want a real, reusable handler for their
own tooling.
## Versioning modes — pick exactly one, and say which one you picked
1. **Plain calendar** (default) — `version_format` uses only
`{current_date}`.
2. **Calendar + build count** — `version_format` includes `{build_count}`
(e.g. `{build_count:03}`), CLI invocation uses `--build`.
3. **Hybrid semver + calendar** — `version_format` includes `{major}`/
`{minor}`/`{patch}`, config has integer `major`/`minor`/`patch` keys, and
`--bump major|minor|patch` bumps the semantic prefix (this writes the new
value back into the config file — a real, persistent change).
Do not mix these up: adding `{build_count}` to a hybrid `version_format`
without also documenting `--build` usage, or vice versa, produces a config
that silently behaves differently than the developer expects.
## Enforced vs. coincidental — the trap to avoid
`version_standard = "python"` is enforced: bumpcalver PEP-440-normalizes the
version string on write. Everything else about `file_type` matching is
**not validated** — bumpcalver will happily run a Python-file regex against
a Ruby file and "succeed" if the text shape happens to match. Do not present
that coincidence as intentional support for a format bumpcalver doesn't
actually have a handler for.
## Known, permanent limitation
XML comments in the prolog (before the root `<element>` opens) are dropped
on `update_version` — an `ElementTree` structural limitation. Comments
nested inside the root element, and the `<?xml ?>` declaration, are
preserved. Mention this if the target XML file has prolog comments.
## Side effects — state these explicitly in your response
- `git_tag = true` / `auto_commit = true` → real git tag / real git commit
on every successful bump. Not a preview.
- `--dry-run` → preview only, writes nothing, no git operations.
- `--json` → single JSON object on stdout, all log lines on stderr. Use for
CI: `` bumpcalver --build --json 2>/dev/null | jq -r '.version' ``.
- `--config-file PATH` / `BUMPCALVER_CONFIG` env var → use a config outside
the cwd; file paths inside it resolve relative to *that file's* directory.
- `--undo` / `--undo-id` / `--list-history` → reads/restores from
`.bumpcalver/backups/` + `bumpcalver-history.json` in the cwd. Mutually
exclusive with every version-bump flag, including `--dry-run`/`--json`/
`--config-file`.
## `.gitignore` — add whenever you configure bumpcalver in a repo that doesn't already have it
```gitignore
# BumpCalver backup and history files
.bumpcalver/
bumpcalver-history.json
```
## Common mistakes to avoid
- Using a dot path for `json`'s `variable` (it must be a plain top-level key).
- Omitting `directive` on a `dockerfile` entry.
- Omitting `pattern` on a `regex` entry, or writing a pattern with more/fewer
than one capture group.
- Silently enabling `git_tag`/`auto_commit` without telling the user this
produces real repository state changes.
- Suggesting `--dry-run` (or `--json`/`--config-file`) alongside
`--undo`/`--undo-id`/`--list-history` — bumpcalver rejects that combination.
- Forgetting `.gitignore` entries for `.bumpcalver/`/`bumpcalver-history.json`.
## Prompt starters
"Configure bumpcalver for this repo: bump `__version__` in
`src/mypkg/__init__.py` and `project.version` in `pyproject.toml` together,
calendar + build count, no git tagging."
"Add hybrid semver + calendar versioning: major/minor starting at 1.0,
calendar build suffix, git tag and commit enabled, updating both
`pyproject.toml` and a Dockerfile's `ARG VERSION`."
Copilot¶
# GitHub Copilot instructions for apps using bumpcalver
`bumpcalver` is a CLI/config-driven calendar-versioning tool — there is no
class or function to import and call from application code. Integration
means authoring a correct `[tool.bumpcalver]` config block and choosing the
right CLI invocation.
## Setup checklist (in order)
- [ ] **Install**: `pip install bumpcalver` (or add to dev dependencies).
- [ ] **Pick config location**: `pyproject.toml`'s `[tool.bumpcalver]` if
the project has one (default choice); otherwise a standalone
`bumpcalver.toml`. If both exist, `pyproject.toml` wins and
`bumpcalver.toml` is ignored — never create both.
- [ ] ⚠️ **Nesting differs by file**: `pyproject.toml` uses
`[tool.bumpcalver]` + `[[tool.bumpcalver.file]]`; standalone
`bumpcalver.toml` is flat — top-level keys + `[[file]]`. Using the
nested form in a standalone file silently produces an empty file list
(no error).
- [ ] **Seed an initial version string** in every target file first —
bumpcalver replaces an existing value, it does not create files or
insert new keys. Missing key → that file's update silently fails
(others still succeed).
- [ ] **List every file that carries a version** (package version
attribute, `pyproject.toml`'s own `project.version`, Dockerfile
`ARG`/`ENV`, etc.) as one `[[tool.bumpcalver.file]]`/`[[file]]` block
each, using the reference table below.
- [ ] **Set `version_format`/`date_format`/`timezone`** — if unsure:
`"{current_date}.{build_count:03}"` / `"%Y.%m.%d"` /
`"America/New_York"`.
- [ ] **Set `git_tag`/`auto_commit` explicitly** — default `false` unless
asked for git automation.
- [ ] **Add `.gitignore` entries** (below).
- [ ] **Verify with `bumpcalver --dry-run`** before a real run. Prints
`No files specified in the configuration.` → recheck the nesting
trap. Expected file missing from preview → recheck the seeded-version
step.
### Minimal example
```toml
[tool.bumpcalver]
version_format = "{current_date}.{build_count:03}"
date_format = "%Y.%m.%d"
timezone = "America/New_York"
git_tag = false
auto_commit = false
[[tool.bumpcalver.file]]
path = "src/mypkg/__init__.py"
file_type = "python"
variable = "__version__"
```
### Typical Python package
```toml
[tool.bumpcalver]
version_format = "{current_date}.{build_count:03}"
date_format = "%Y.%m.%d"
timezone = "America/New_York"
git_tag = true
auto_commit = false
[[tool.bumpcalver.file]]
path = "pyproject.toml"
file_type = "toml"
variable = "project.version"
version_standard = "python"
[[tool.bumpcalver.file]]
path = "src/mypkg/__init__.py"
file_type = "python"
variable = "__version__"
version_standard = "python"
```
## Checklist (complete every item)
- [ ] `[tool.bumpcalver]` table added to `pyproject.toml`, or a standalone
`bumpcalver.toml`, with `version_format`, `date_format`, `timezone`.
- [ ] One `[[tool.bumpcalver.file]]` block per file that carries a version
string, each with the correct `file_type` and matching
`variable`/`directive`/`pattern` (see table).
- [ ] Exactly one versioning mode chosen (plain calendar / calendar+build /
hybrid semver+calendar) — not a mix.
- [ ] If pre-release suffixes are needed: `beta_format`/`rc_format`/
`release_format` config keys added.
- [ ] `git_tag`/`auto_commit` values stated explicitly — `true` means a
**real git tag/commit** on every run, not a preview.
- [ ] `.bumpcalver/` and `bumpcalver-history.json` added to `.gitignore`.
## `file_type` → `variable` reference table
| `file_type` | `variable` is... | Extra required key |
|---|---|---|
| `python` | a Python variable name, e.g. `__version__` | — |
| `toml` | a dot path, e.g. `project.version` | — |
| `yaml` | a dot path, e.g. `configuration.version` | — |
| `json` | a **plain top-level key** — not a dot path | — |
| `xml` | an `ElementTree.find()` path, e.g. `version` | — |
| `dockerfile` | a variable name | `directive` = `"ARG"` or `"ENV"` |
| `makefile` | a Makefile variable name | — |
| `properties` | a `KEY=value` key | — |
| `env` | a `.env` `KEY=value` key | — |
| `setup.cfg` | a dot path or simple key | — |
| `text` | not used (whole file is the version) | — |
| `regex` | any name | `pattern` = regex, exactly one capture group |
⚠️ **`json` and `toml`/`yaml` look similar but differ**: JSON's `variable`
is a plain top-level key, TOML/YAML's is a dot-separated path. Using a dot
path for JSON silently fails to find the key.
## Versioning modes (pick one)
1. **Plain calendar** (default) — `version_format` uses only `{current_date}`.
2. **Calendar + build count** — add `{build_count}` to `version_format`,
invoke with `--build`.
3. **Hybrid semver + calendar** — add `{major}`/`{minor}`/`{patch}` to
`version_format`, add integer `major`/`minor`/`patch` config keys, bump
with `--bump major|minor|patch` (writes the new value back to config).
## Enforced vs. cosmetic
- `version_standard = "python"` → **enforced** PEP-440 normalization on write.
- `file_type` → **not validated** against the file's real content. A
"working" mismatched `file_type` (e.g. `python` on a Ruby file) is
coincidental regex overlap, not real support — use `file_type = "regex"`
with an explicit `pattern` for unsupported `KEY = "value"` formats instead.
## Known limitation
`xml` drops comments in the prolog (before the root element opens) on
write — preserves the `<?xml ?>` declaration and comments nested inside the
root element. `ElementTree` structural limitation, not a bug.
## Side effects to call out explicitly
- `git_tag = true` / `auto_commit = true` — real git tag / real git commit.
- `--dry-run` — preview only, no writes, no git operations.
- `--json` — one JSON object on stdout, log lines move to stderr; use for
CI: `bumpcalver --build --json 2>/dev/null | jq -r '.version'`.
- `--config-file PATH` / `BUMPCALVER_CONFIG` — config outside cwd; paths in
it resolve relative to *its own* directory.
- `--undo` / `--undo-id` / `--list-history` — mutually exclusive with every
version-bump flag (including `--dry-run`/`--json`/`--config-file`).
## `.gitignore` snippet
```gitignore
# BumpCalver backup and history files
.bumpcalver/
bumpcalver-history.json
```
## Common mistakes to avoid
- ❌ Dot path for a `json` file's `variable`.
- ❌ `dockerfile` entry missing `directive`.
- ❌ `regex` entry missing `pattern`, or a pattern without exactly one
capture group.
- ❌ Enabling `git_tag`/`auto_commit` without flagging the real side effect.
- ❌ Combining `--dry-run`/`--json`/`--config-file` with the undo flags.
- ❌ Forgetting the `.gitignore` entries.
## Prompt starters
"Set up bumpcalver: bump `__version__` in `src/mypkg/__init__.py` and
`project.version` in `pyproject.toml` together, calendar + build count, no
git tagging."
"Add hybrid semver + calendar versioning: major/minor at 1.0, calendar
suffix, git tag and commit on, updating `pyproject.toml` and a Dockerfile's
`ARG VERSION`."
What these instructions cover¶
- A step-by-step setup procedure from a blank repo: install, decide between
pyproject.tomland a standalonebumpcalver.toml(including the flat-vs- nested key trap between the two), seed an initial version string in every target file (bumpcalver replaces existing values, it does not create files or insert keys), map every file to afile_type, pick saneversion_format/date_format/timezonedefaults, and verify with--dry-runbefore a real run — plus copy-paste-ready minimal and "typical Python package" example configs, both verified against the real CLI. - All 12 built-in
file_types and whatvariablemeans for each (a plain key vs. a dot path vs. anElementTree.find()path — these are genuinely different mechanisms, not variations of one setting). - The three versioning modes (plain calendar, calendar + build count, hybrid semver + calendar) and how to pick one.
- Pre-release suffix flags and their config keys.
- Which config keys have real side effects (
git_tag/auto_commitcreate an actual git tag/commit, not a preview). --dry-run,--json, and--config-filefor previewing, scripting, and monorepo/cross-directory use.- The undo/backup system and the
.gitignoreentries a new bumpcalver integration should add. - One permanent, structural limitation (XML prolog comments) worth knowing about up front.
What these instructions do NOT cover¶
Being explicit about gaps matters more than it might seem — an AI assistant reading documentation will trust silence as "not applicable," which is worse than an honest "not covered yet":
- The
bumpcalver.handlersplugin/entry-point mechanism for registering a customfile_typefrom a third-party package is mentioned in passing but not walked through step by step — see the development guide for the full recipe if a project needs a file format with no built-in or regex-compatible handler. - Undo internals (backup file naming,
bumpcalver-history.json's exact schema) beyond "these two paths exist and should be gitignored" — see the Undo documentation for the full mechanics. - CI/CD recipes beyond the single
--json/jqexample already in the instructions — see the CLI Reference for the full--jsonpayload shape per case.
Security¶
--output is treated as untrusted input, not a trusted human-typed path —
the entire premise of this feature is that an AI assistant may invoke this
CLI directly, and a misdirected instruction, a reasoning bug, or a prompt
injection could produce an adversarial path argument. _resolve_output_path
resolves the destination (following symlinks) and rejects anything that
isn't a descendant of the current working directory, using Path.parents
containment rather than a string-prefix check (a prefix check would wrongly
treat a sibling directory like project-evil/ as being inside project/).
This is covered by dedicated regression tests
(tests/test_ai_instructions.py) that must not be weakened or removed.
Packaging¶
The three profile .md files ship as package data under
bumpcalver/assets/ai/ — verified with a real python -m build +
install-into-a-clean-venv check, not just editable-mode testing, since
packaging misconfiguration is easy to miss in dev mode and only surfaces for
someone doing a real pip install.
Keeping this in sync¶
If you're changing bumpcalver's public config schema (a new file_type, a
new CLI flag, a new config key with a real side effect), update
src/bumpcalver/assets/ai/*.md in the same change — the "Full instructions
by profile" section above regenerates from those files automatically at
mkdocs build time (via scripts/mkdocs_hooks.py), so there's no separate
docs-page edit to remember; editing the source files is the whole job.
A regression test
(test_get_app_instructions_documents_every_builtin_file_type) asserts
every file_type in _HANDLER_REGISTRY is mentioned in the generic
profile, but that only catches missing file types — it can't catch stale
prose about CLI flags or config keys, so this has to be a deliberate habit,
not something a test alone will enforce.