Developer Guide#
Installation From Source (Development)#
Clone the repository and install in editable mode with the dev dependency group (which provides pytest, pre-commit, and ipython):
pip install -e . --group dev
Project Layout#
historia/
├── src/historia/ # Main package source
│ ├── _cli.py # CLI entry points
│ └── data/
│ └── github/ # GitHub data fetch/dump/update APIs
├── tests/ # Pytest test suite
├── docs/ # Sphinx documentation source
├── AGENTS.md # Agent/AI contributor instructions
├── CHANGELOG.md # Release changelog
└── pyproject.toml # Project metadata and tool configuration
Testing#
This project uses pytest for its test suite.
python -m pytest
Assertion Style#
Always place the actual (observed) value on the left and the expected value on the right:
# Correct
assert actual_value == expected_value
# Incorrect
assert expected_value == actual_value
AI-Generated Tests#
Tests written or substantially assisted by AI must be marked with the ai_generated marker:
import pytest
@pytest.mark.ai_generated
def test_something():
...
Use pytest.mark.parametrize wherever appropriate to reduce test duplication.
Code Quality (Pre-commit Hooks)#
This project uses pre-commit to enforce code quality automatically before each commit.
The configured hooks are:
black — code formatting
ruff — linting and import sorting (with auto-fix)
codespell — spell checking
mypy — static type checking
Install the hooks once after cloning:
pre-commit install
Run all hooks manually against all files (recommended before opening a PR):
pre-commit run --all-files
Pre-commit will auto-fix most formatting and lint issues. Re-run the command afterward to confirm everything passes.
CLI#
The Historia package exposes a single entry point:
historia— primary entrypoint
Commands are organized into sub-groups:
historia update— data managementhistoria update github— fetch raw GitHub activity data for a user
historia project— GitHub Project managementhistoria project create— create a new GitHub Project pagehistoria project populate— populate a project from fetched datahistoria project update dates— update item date fields in a projecthistoria project transition— transition project items between statuses
Since every command requires at least one option, running any command or sub-group without arguments automatically prints its help text:
historia
historia update
historia project
Changelog#
Add a short description of any user-facing change to the ## Upcoming section of CHANGELOG.md under the appropriate subsection:
### 🚀 Enhancement— new features### 🐛 Bug Fix— bug fixes### 📝 Documentation— documentation-only changes### 🏠 Internal— refactors, tooling, CI, and test infrastructure### 🔩 Dependency Updates— dependency-only changes
Include the GitHub PR link at the end of each entry:
- Brief description of the change. ([#N](https://github.com/CodyCBakerPhD/historia/pull/N))
Building Documentation#
Building Locally#
Install the docs dependencies:
pip install -e . --group docs
Build the HTML output:
python -m sphinx -b html docs docs/_build/html
Open docs/_build/html/index.html in your browser to preview the result.
AI Usage Addendum#
Materials across repositories in this organization have been prepared with the assistance of agentic AI coding tools and large language models (LLMs), alongside direct human authoring and supervision.
Our working practice is: 👤 Human review and accountability. We strive to have final versions of all work — prose, code, figures, and specifications — to be reviewed and/or edited by human authors, who remain accountable for the content. 🪪 Transparent annotation. Where AI tools materially contributed to a commit, we strive to annotate that commit adequately and trustworthily (for example, via a Co-Authored-By trailer identifying the tool and model version), so that the provenance of individual changes can be inspected in the git history. 🔍 Inspectable provenance. Because all work is developed in public git repositories with pull-request review, readers can trace portions of the materials which involved AI assistance.
AI tools are used as assistive instruments; they do not substitute for the scientific judgment, domain expertise, or editorial responsibility of the human authors.
Agent / AI Contributor Instructions#
Agent instructions#
Commits and PRs#
Always run
pre-commitbefore committing and pushing changesAlways link PRs to issues when possible
PR titles should be human-readable and in the past tense. They should NOT use conventional commit style.
Every commit must include a
Co-Authored-Bytrailer identifying your tool name and version and your underlying model and version. Format (replace all<…>placeholders with actual values):Co-Authored-By: <Tool> <tool-version> / <Model> <model-version> <noreply@vendor-domain>
Versioning and changelog#
Bump the version in
pyproject.tomlonce per PR when any file undersrc/orpyproject.tomlitself changes. Do NOT bump for changes that are purely CI/workflow, documentation, or configuration (e.g., GitHub Actions workflows,AGENTS.md,README.mdbadges).Add a short entry to the
## Upcomingsection ofCHANGELOG.mdunder the appropriate subsection (### 🚀 Enhancement,### 🐛 Bug Fix,### 📝 Documentation,### 🔩 Dependency Updates,### 🏠 Internal). Include the PR link at the end of each entry in the format([#N](https://github.com/<org>/<repo>/pull/N)). Create the## Upcomingsection or subsection if it does not yet exist.
Code style#
Require keyword-only arguments
(*, ...)for multi-input functions. For any function with exactly one caller-supplied parameter (excludingselfandcls), require positional-only usage with the/designator.Always add new imports at the top of the file. The only exception is when a local import is needed to avoid a circular dependency.
For external dependencies, use the full module import style (e.g.,
import xyz; xyz.abc) rather thanfrom xyz import abc.For internal imports, always use relative style (e.g.,
from .foo import bar).Prefer assigning return values to named locals before
returnwhen this improves readability and debugger breakpoint placement.Avoid excessive em-dashes, colons, and semicolons in written text such as documentation. Prefer breaking into separate, shorter sentences instead.
Favor defining one-word names for CLI flags, then map those onto longer, more explicit keyword arguments at the API level.
Keep inline comments sparse. Only explain non-obvious “why”, not “what” the code does. Prefer self-documenting code and clear names over narration; do not annotate routine logic.
Tests#
To the best of your ability, ensure tests are passing before pushing.
Follow assertion style: actual on left, expected on right.
Always mark AI-generated tests with the
ai_generatedpytest marker.Use
pytest.mark.parametrizewherever appropriate to reduce duplication in test cases.Avoid importing private API (names with a leading underscore) in tests. Always import from what is publicly exposed through
__init__.pyfiles.When monkeypatching internal imports in tests, target the importing module’s binding (e.g.,
foo.baz), not the original definition module (e.g.,foo._bar.baz).
Module and API conventions#
Never expose private names (those with a leading underscore) in any module’s
__all__.Never include code other than imports,
__all__, simple import errors, or magic__dir__overrides in any__init__.pyfile.Do not add compatibility aliases when renaming functions. Update all call sites to the canonical name instead.