diff --git a/.gitignore b/.gitignore
index 3149237..65fc8e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 .venv/
 __pycache__/
 *.egg-info/
+.pygitweb/
diff --git a/assets/style.css b/assets/style.css
new file mode 100644
index 0000000..561524c
--- /dev/null
+++ b/assets/style.css
@@ -0,0 +1,319 @@
+body {
+  font-family: Helvetica, Arial, sans-serif;
+  font-size: 12px;
+  /* do not increase min-width as some may use split screens */
+  min-width: 800px;
+  color: #999;
+}
+
+h1 {
+  font-size: 24px;
+  color: black;
+}
+
+h2 {
+  font-size: 16px;
+  color: black;
+}
+
+p {
+  color: black;
+}
+
+a {
+  color: #999;
+}
+
+table {
+  border-collapse: collapse;
+}
+
+/******************************
+ * SUMMARY INFORMATION
+ ******************************/
+#environment td {
+  padding: 5px;
+  border: 1px solid #e6e6e6;
+  vertical-align: top;
+}
+#environment tr:nth-child(odd) {
+  background-color: #f6f6f6;
+}
+#environment ul {
+  margin: 0;
+  padding: 0 20px;
+}
+
+/******************************
+ * TEST RESULT COLORS
+ ******************************/
+span.passed,
+.passed .col-result {
+  color: green;
+}
+
+span.skipped,
+span.xfailed,
+span.rerun,
+.skipped .col-result,
+.xfailed .col-result,
+.rerun .col-result {
+  color: orange;
+}
+
+span.error,
+span.failed,
+span.xpassed,
+.error .col-result,
+.failed .col-result,
+.xpassed .col-result {
+  color: red;
+}
+
+.col-links__extra {
+  margin-right: 3px;
+}
+
+/******************************
+ * RESULTS TABLE
+ *
+ * 1. Table Layout
+ * 2. Extra
+ * 3. Sorting items
+ *
+ ******************************/
+/*------------------
+ * 1. Table Layout
+ *------------------*/
+#results-table {
+  border: 1px solid #e6e6e6;
+  color: #999;
+  font-size: 12px;
+  width: 100%;
+}
+#results-table th,
+#results-table td {
+  padding: 5px;
+  border: 1px solid #e6e6e6;
+  text-align: left;
+}
+#results-table th {
+  font-weight: bold;
+}
+
+/*------------------
+ * 2. Extra
+ *------------------*/
+.logwrapper {
+  max-height: 230px;
+  overflow-y: scroll;
+  background-color: #e6e6e6;
+}
+.logwrapper.expanded {
+  max-height: none;
+}
+.logwrapper.expanded .logexpander:after {
+  content: "collapse [-]";
+}
+.logwrapper .logexpander {
+  z-index: 1;
+  position: sticky;
+  top: 10px;
+  width: max-content;
+  border: 1px solid;
+  border-radius: 3px;
+  padding: 5px 7px;
+  margin: 10px 0 10px calc(100% - 80px);
+  cursor: pointer;
+  background-color: #e6e6e6;
+}
+.logwrapper .logexpander:after {
+  content: "expand [+]";
+}
+.logwrapper .logexpander:hover {
+  color: #000;
+  border-color: #000;
+}
+.logwrapper .log {
+  min-height: 40px;
+  position: relative;
+  top: -50px;
+  height: calc(100% + 50px);
+  border: 1px solid #e6e6e6;
+  color: black;
+  display: block;
+  font-family: "Courier New", Courier, monospace;
+  padding: 5px;
+  padding-right: 80px;
+  white-space: pre-wrap;
+}
+
+div.media {
+  border: 1px solid #e6e6e6;
+  float: right;
+  height: 240px;
+  margin: 0 5px;
+  overflow: hidden;
+  width: 320px;
+}
+
+.media-container {
+  display: grid;
+  grid-template-columns: 25px auto 25px;
+  align-items: center;
+  flex: 1 1;
+  overflow: hidden;
+  height: 200px;
+}
+
+.media-container--fullscreen {
+  grid-template-columns: 0px auto 0px;
+}
+
+.media-container__nav--right,
+.media-container__nav--left {
+  text-align: center;
+  cursor: pointer;
+}
+
+.media-container__viewport {
+  cursor: pointer;
+  text-align: center;
+  height: inherit;
+}
+.media-container__viewport img,
+.media-container__viewport video {
+  object-fit: cover;
+  width: 100%;
+  max-height: 100%;
+}
+
+.media__name,
+.media__counter {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-around;
+  flex: 0 0 25px;
+  align-items: center;
+}
+
+.collapsible td:not(.col-links) {
+  cursor: pointer;
+}
+.collapsible td:not(.col-links):hover::after {
+  color: #bbb;
+  font-style: italic;
+  cursor: pointer;
+}
+
+.col-result {
+  width: 130px;
+}
+.col-result:hover::after {
+  content: " (hide details)";
+}
+
+.col-result.collapsed:hover::after {
+  content: " (show details)";
+}
+
+#environment-header h2:hover::after {
+  content: " (hide details)";
+  color: #bbb;
+  font-style: italic;
+  cursor: pointer;
+  font-size: 12px;
+}
+
+#environment-header.collapsed h2:hover::after {
+  content: " (show details)";
+  color: #bbb;
+  font-style: italic;
+  cursor: pointer;
+  font-size: 12px;
+}
+
+/*------------------
+ * 3. Sorting items
+ *------------------*/
+.sortable {
+  cursor: pointer;
+}
+.sortable.desc:after {
+  content: " ";
+  position: relative;
+  left: 5px;
+  bottom: -12.5px;
+  border: 10px solid #4caf50;
+  border-bottom: 0;
+  border-left-color: transparent;
+  border-right-color: transparent;
+}
+.sortable.asc:after {
+  content: " ";
+  position: relative;
+  left: 5px;
+  bottom: 12.5px;
+  border: 10px solid #4caf50;
+  border-top: 0;
+  border-left-color: transparent;
+  border-right-color: transparent;
+}
+
+.hidden, .summary__reload__button.hidden {
+  display: none;
+}
+
+.summary__data {
+  flex: 0 0 550px;
+}
+.summary__reload {
+  flex: 1 1;
+  display: flex;
+  justify-content: center;
+}
+.summary__reload__button {
+  flex: 0 0 300px;
+  display: flex;
+  color: white;
+  font-weight: bold;
+  background-color: #4caf50;
+  text-align: center;
+  justify-content: center;
+  align-items: center;
+  border-radius: 3px;
+  cursor: pointer;
+}
+.summary__reload__button:hover {
+  background-color: #46a049;
+}
+.summary__spacer {
+  flex: 0 0 550px;
+}
+
+.controls {
+  display: flex;
+  justify-content: space-between;
+}
+
+.filters,
+.collapse {
+  display: flex;
+  align-items: center;
+}
+.filters button,
+.collapse button {
+  color: #999;
+  border: none;
+  background: none;
+  cursor: pointer;
+  text-decoration: underline;
+}
+.filters button:hover,
+.collapse button:hover {
+  color: #ccc;
+}
+
+.filter__label {
+  margin-right: 10px;
+}
diff --git a/pygitweb/actions.py b/pygitweb/actions.py
index 88c5bcf..846b3da 100644
--- a/pygitweb/actions.py
+++ b/pygitweb/actions.py
@@ -336,7 +336,7 @@ def git_object(project: str, h: str | None) -> Response:
 	raise HTTPException(status_code=404, detail="Unknown object type")
 
 
-def git_summary(project: str) -> HTMLResponse:
+def git_summary(project: str, extra_rows: list[list[str]] | None = None) -> HTMLResponse:
 	"""Project summary page. Port of git_summary."""
 	descr = git_get_project_description(project) or ""
 	owner = git_get_project_owner(project) or ""
@@ -355,30 +355,33 @@ def git_summary(project: str) -> HTMLResponse:
 		proj_q = quote(project, safe="")
 		board_value = f'<a href="/board/create?project={proj_q}"{grey_style}>create board</a>'
 
+	rows: list[list[str]] = [
+		["Owner", esc_html(owner)],
+		[
+			(
+				'<label for="summary-ref-select">Ref</label> '
+				'<select id="summary-ref-select">'
+				'<option value="HEAD" selected>HEAD</option>'
+				"</select>"
+			),
+			(
+				f'<a id="summary-ref-commit-link" href="{initial_ref_state["commit_href"]}">'
+				f"{initial_ref_state['display']}</a>: "
+				f'<a id="summary-ref-browse-link" href="{initial_ref_state["browse_href"]}">browse</a> - '
+				f'<a id="summary-ref-log-link" href="{initial_ref_state["log_href"]}">log</a> - '
+				f'<a id="summary-ref-shortlog-link" href="{initial_ref_state["shortlog_href"]}">shortlog</a>'
+			),
+		],
+		["Branches", f"<a href='/project/{project}?a=heads'>view branches</a>"],
+		["Tags", f"<a href='/project/{project}?a=tags'>view tags</a>"],
+		["Remotes", f"<a href='/project/{project}?a=remotes'>view remotes</a>"],
+		["Board", board_value],
+	]
+	if extra_rows:
+		rows.extend(extra_rows)
 	table = env.get_template("table.html").render(
 		cols=["Field", "Value"],
-		rows=[
-			["Owner", esc_html(owner)],
-			[
-				(
-					'<label for="summary-ref-select">Ref</label> '
-					'<select id="summary-ref-select">'
-					'<option value="HEAD" selected>HEAD</option>'
-					"</select>"
-				),
-				(
-					f'<a id="summary-ref-commit-link" href="{initial_ref_state["commit_href"]}">'
-					f"{initial_ref_state['display']}</a>: "
-					f'<a id="summary-ref-browse-link" href="{initial_ref_state["browse_href"]}">browse</a> - '
-					f'<a id="summary-ref-log-link" href="{initial_ref_state["log_href"]}">log</a> - '
-					f'<a id="summary-ref-shortlog-link" href="{initial_ref_state["shortlog_href"]}">shortlog</a>'
-				),
-			],
-			["Branches", f"<a href='/project/{project}?a=heads'>view branches</a>"],
-			["Tags", f"<a href='/project/{project}?a=tags'>view tags</a>"],
-			["Remotes", f"<a href='/project/{project}?a=remotes'>view remotes</a>"],
-			["Board", board_value],
-		],
+		rows=rows,
 	)
 	pre = PREAMBLE.render(title=f"{esc_html(settings.SITE_NAME)} - {project}", site_name=settings.SITE_NAME)
 	body_parts = [f"{pre}<h1>{esc_html(project)}</h1>"]
diff --git a/pygitweb/api/action.py b/pygitweb/api/action.py
new file mode 100644
index 0000000..bb34513
--- /dev/null
+++ b/pygitweb/api/action.py
@@ -0,0 +1,12 @@
+from fastapi import Request
+from pygitweb.api.project import Project
+
+class Action(object):
+    """
+    Action: A per-project action provided by a plugin.
+    """
+    def action_name(self) -> str:
+        return "base-action"
+    
+    def action(self, project: Project, user: request: Request = None) -> None:
+        raise NotImplementedError(f"Action {self.action_name()} is not implemented")
diff --git a/pygitweb/api/subpage.py b/pygitweb/api/subpage.py
new file mode 100644
index 0000000..70dfc34
--- /dev/null
+++ b/pygitweb/api/subpage.py
@@ -0,0 +1,16 @@
+
+
+class Subpage:
+	"""
+	Subpage: A per-project subpage provided by a plugin.
+	"""
+
+	def subpage_name(self) -> str:
+		raise NotImplementedError("subpage_name() must be implemented")
+
+	def link_name(self, project: str) -> str | None:
+		return None
+
+	def subpage_html(self, project: str) -> str | None:
+		return None
+
diff --git a/pygitweb/main.py b/pygitweb/main.py
index 489a534..c31b17b 100644
--- a/pygitweb/main.py
+++ b/pygitweb/main.py
@@ -41,6 +41,7 @@ from pygitweb.actions import (
 )
 from pygitweb.api.plugins.project_zip import ProjectZip
 from pygitweb.api.project import Project
+from pygitweb.api.subpage import Subpage
 from pygitweb.config import ACTIONS, check_loadavg, settings
 from pygitweb.formatting import age_string, esc_html
 from pygitweb.git_helpers import git_get_references, git_get_type
@@ -57,6 +58,11 @@ from pygitweb.templates_env import POSTAMBLE, PREAMBLE, env
 from pygitweb.timeline_cache import get_all_timeline_events, warm_timeline_cache_async
 from pygitweb.validation import is_valid_action, is_valid_pathname, is_valid_project
 
+try:
+	from pygitweb_pytesthtml.subpage_pytesthtml import SubpagePytestHtml
+except ImportError:
+	SubpagePytestHtml = None
+
 with open("pygitweb/README.md", encoding="utf-8") as _readme_file:
 	_app_description = _readme_file.read()
 
@@ -68,6 +74,10 @@ app = FastAPI(
 	version=__meta__.__version__,
 )
 
+SUBPAGES: list[Subpage] = []
+if SubpagePytestHtml is not None:
+	SUBPAGES.append(SubpagePytestHtml())
+
 # Todo handle with nginx route
 _static_dir = Path(__file__).parent / "static"
 if _static_dir.is_dir():
@@ -181,6 +191,28 @@ def _truncate_activity_description(description: str | None, max_len: int = 80) -
 	return description
 
 
+def _project_subpage_rows(project: str) -> list[list[str]]:
+	project_enc = quote(project, safe="/")
+	rows: list[list[str]] = []
+	for subpage in SUBPAGES:
+		link_label = subpage.link_name(project)
+		if not link_label:
+			continue
+		subpage_name = subpage.subpage_name()
+		rows.append([
+			esc_html(link_label),
+			f'<a href="/project/{project_enc}/subpage/{quote(subpage_name, safe="")}">view</a>',
+		])
+	return rows
+
+
+def _inject_subpage_stylesheet(html_content: str, stylesheet_href: str) -> str:
+	link_tag = f'<link rel="stylesheet" href="{stylesheet_href}">'
+	if "<head" in html_content.lower():
+		return html_content.replace("</head>", f"{link_tag}</head>", 1)
+	return f"{link_tag}{html_content}"
+
+
 # ---------- Routes (no project) ----------
 
 
@@ -489,6 +521,39 @@ def project_summary_ref_state(
 	return summary_ref_state(project, ref)
 
 
+@app.get("/project/{project:path}/subpage/{subpage_name}", response_class=HTMLResponse)
+def project_subpage(
+	project: str,
+	subpage_name: str,
+	raw: Annotated[bool, Query()] = False,
+) -> HTMLResponse:
+	_validate_project(project)
+	for subpage in SUBPAGES:
+		if subpage.subpage_name() != subpage_name:
+			continue
+		content = subpage.subpage_html(project)
+		if content is None:
+			raise HTTPException(status_code=404, detail="No content for subpage")
+		content_lc = content.lstrip().lower()
+		pre = PREAMBLE.render(
+			title=f"{esc_html(subpage.link_name(project) or subpage_name)} - {esc_html(project)}",
+			site_name=settings.SITE_NAME,
+		)
+		if content_lc.startswith("<!doctype html") or "<html" in content_lc:
+			if raw:
+				return HTMLResponse(_inject_subpage_stylesheet(content, "/static/main.css"))
+			project_enc = quote(project, safe="/")
+			subpage_enc = quote(subpage_name, safe="")
+			iframe_src = f"/project/{project_enc}/subpage/{subpage_enc}?raw=true"
+			return HTMLResponse(
+				f"{pre}<h1>{esc_html(project)}</h1>"
+				f'<iframe class="subpage-frame" src="{iframe_src}" title="{esc_html(subpage_name)}"></iframe>'
+				f"{POSTAMBLE}"
+			)
+		return HTMLResponse(f"{pre}<h1>{esc_html(project)}</h1>{content}{POSTAMBLE}")
+	raise HTTPException(status_code=404, detail="Unknown subpage")
+
+
 @app.get("/project/{project:path}", response_class=HTMLResponse)
 def dispatch(
 	request: Request,
@@ -537,7 +602,7 @@ def dispatch(
 		raise HTTPException(status_code=400, detail="Project not needed for this action")
 	# Route to handler
 	if action == "summary":
-		return git_summary(project)
+		return git_summary(project, extra_rows=_project_subpage_rows(project))
 	if action == "tree":
 		return git_tree(project, hash_param, file_name)
 	if action in ("blob", "blob_plain"):
diff --git a/pygitweb/static/main.css b/pygitweb/static/main.css
index 50c5ce1..5faf3f8 100644
--- a/pygitweb/static/main.css
+++ b/pygitweb/static/main.css
@@ -380,12 +380,25 @@ th, td {
 	border-bottom: 1px solid var(--pgw-border-muted);
 }
 
+p {
+	color: var(--pgw-text);
+}
+
 th {
 	background-color: var(--pgw-accent-bg);
 	color: var(--pgw-accent-text);
 	font-weight: 600;
 }
 
+#environment {
+	background-color: var(--pgw-bg-raised);
+	color: var(--pgw-text);
+}
+
+#environment tr:nth-child(2n+1) {
+	background-color: var(--pgw-table-stripe);
+}
+
 tbody tr {
 	&:nth-child(even) {
 		background-color: var(--pgw-table-stripe);
@@ -826,3 +839,12 @@ tbody tr {
 		resize: vertical;
 	}
 }
+
+.subpage-frame {
+	display: block;
+	width: 100%;
+	height: 82vh;
+	min-height: 42rem;
+	border: 1px solid var(--pgw-border);
+	background-color: var(--pgw-bg-raised);
+}
diff --git a/pygitweb_pytesthtml/README.md b/pygitweb_pytesthtml/README.md
new file mode 100644
index 0000000..3484995
--- /dev/null
+++ b/pygitweb_pytesthtml/README.md
@@ -0,0 +1,7 @@
+# pygitweb_pytesthtml: PyGitWeb Plugin for pytest-html
+
+Do you have a python project with tests and want a test dashboard integrated into pygitweb?
+
+Then this plugin is for you! Possible only thanks to the great work done by the contributors to pytest-html, and of course pytest itself.
+
+This is the inaugural first-party plugin for PyGitWeb and will likely be installed by default... but can always be disabled.
diff --git a/pygitweb_pytesthtml/action_pytesthtml.py b/pygitweb_pytesthtml/action_pytesthtml.py
new file mode 100644
index 0000000..4e0a05b
--- /dev/null
+++ b/pygitweb_pytesthtml/action_pytesthtml.py
@@ -0,0 +1,15 @@
+from pygitweb.api.action import Action
+from pygitweb.api.project import Project
+from fastapi import Request
+
+import subprocess
+
+def ActionPytestHtml(Action):
+    """
+    ActionPytestHtml: Run pytest and render the results.
+    """
+    def action_name(self) -> str:
+        return "pytesthtml_run"
+    
+    def action(self, project: Project, user: request: Request = None) -> None:
+        subprocess.run(["pytest", "--html=.pygitweb/pytest_report.html", "--self-contained-html"], cwd=project.path)
\ No newline at end of file
diff --git a/pygitweb_pytesthtml/pyproject.toml b/pygitweb_pytesthtml/pyproject.toml
new file mode 100644
index 0000000..02c00b1
--- /dev/null
+++ b/pygitweb_pytesthtml/pyproject.toml
@@ -0,0 +1,9 @@
+[project]
+name = "pygitweb_pytesthtml"
+version = "0.1.0"
+description = "PyGitWeb Plugin: pytest-html dashboard"
+readme = "README.md"
+requires-python = ">=3.11"
+dependencies = [
+    "pytest-html>=4.2.0",
+]
diff --git a/pygitweb_pytesthtml/subpage_pytesthtml.py b/pygitweb_pytesthtml/subpage_pytesthtml.py
new file mode 100644
index 0000000..82670c3
--- /dev/null
+++ b/pygitweb_pytesthtml/subpage_pytesthtml.py
@@ -0,0 +1,22 @@
+from pathlib import Path
+
+from pygitweb.api.subpage import Subpage
+from pygitweb.config import settings
+
+
+class SubpagePytestHtml(Subpage):
+	"""
+	SubpagePytestHtml: Render the latest Pytest results for a project.
+	"""
+
+	def subpage_name(self) -> str:
+		return "pytesthtml"
+
+	def link_name(self, project: str) -> str | None:
+		return "Pytest Results"
+
+	def subpage_html(self, project: str) -> str | None:
+		report_path = Path(settings.PROJECTROOT) / project / ".pygitweb" / "pytest_report.html"
+		if not report_path.is_file():
+			return "<p>No pytest report found.</p>"
+		return report_path.read_text(encoding="utf-8")
diff --git a/pyproject.toml b/pyproject.toml
index 8471c75..70d33da 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,7 +13,7 @@ dev = [
 ]
 
 [tool.uv.workspace]
-members = ["postgit", "pygittools", "pygitweb"]
+members = ["postgit", "pygittools", "pygitweb", "pygitweb_pytesthtml"]
 
 [tool.uv]
 package = false
diff --git a/uv.lock b/uv.lock
index 4cab041..a654d5e 100644
--- a/uv.lock
+++ b/uv.lock
@@ -7,6 +7,7 @@ members = [
     "postgit",
     "pygittools",
     "pygitweb",
+    "pygitweb-pytesthtml",
     "pygitweb-workspace",
 ]
 
@@ -952,6 +953,7 @@ dependencies = [
     { name = "fastapi", extra = ["standard-no-fastapi-cloud-cli"] },
     { name = "jinja2" },
     { name = "orjson" },
+    { name = "pydantic-settings" },
     { name = "pygit2" },
     { name = "pygittools" },
     { name = "python-multipart" },
@@ -963,6 +965,7 @@ requires-dist = [
     { name = "fastapi", extras = ["standard-no-fastapi-cloud-cli"], specifier = ">=0.104.0" },
     { name = "jinja2", specifier = ">=3.1.0" },
     { name = "orjson", specifier = ">=0.19.0" },
+    { name = "pydantic-settings", specifier = ">=2.13.0" },
     { name = "pygit2", specifier = ">=1.12.0" },
     { name = "pygittools", editable = "pygittools" },
     { name = "python-multipart", specifier = ">=0.0.6" },
@@ -970,6 +973,17 @@ requires-dist = [
 ]
 
 [[package]]
+name = "pygitweb-pytesthtml"
+version = "0.1.0"
+source = { virtual = "pygitweb_pytesthtml" }
+dependencies = [
+    { name = "pytest-html" },
+]
+
+[package.metadata]
+requires-dist = [{ name = "pytest-html", specifier = ">=4.2.0" }]
+
+[[package]]
 name = "pygitweb-workspace"
 version = "0.0.0"
 source = { virtual = "." }
@@ -1016,6 +1030,32 @@ wheels = [
 ]
 
 [[package]]
+name = "pytest-html"
+version = "4.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "jinja2" },
+    { name = "pytest" },
+    { name = "pytest-metadata" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c4/08/2076aa09507e51c1119d16a84c6307354d16270558f1a44fc9a2c99fdf1d/pytest_html-4.2.0.tar.gz", hash = "sha256:b6a88cba507500d8709959201e2e757d3941e859fd17cfd4ed87b16fc0c67912", size = 108634, upload-time = "2026-01-19T11:25:26.471Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/84/47/07046e0acedc12fe2bae79cf6c73ad67f51ae9d67df64d06b0f3eac73d36/pytest_html-4.2.0-py3-none-any.whl", hash = "sha256:ff5caf3e17a974008e5816edda61168e6c3da442b078a44f8744865862a85636", size = 23801, upload-time = "2026-01-19T11:25:25.008Z" },
+]
+
+[[package]]
+name = "pytest-metadata"
+version = "3.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a6/85/8c969f8bec4e559f8f2b958a15229a35495f5b4ce499f6b865eac54b878d/pytest_metadata-3.1.1.tar.gz", hash = "sha256:d2a29b0355fbc03f168aa96d41ff88b1a3b44a3b02acbe491801c98a048017c8", size = 9952, upload-time = "2024-02-12T19:38:44.887Z" }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/3e/43/7e7b2ec865caa92f67b8f0e9231a798d102724ca4c0e1f414316be1c1ef2/pytest_metadata-3.1.1-py3-none-any.whl", hash = "sha256:c8e0844db684ee1c798cfa38908d20d67d0463ecb6137c72e91f418558dd5f4b", size = 11428, upload-time = "2024-02-12T19:38:42.531Z" },
+]
+
+[[package]]
 name = "python-dotenv"
 version = "1.2.2"
 source = { registry = "https://pypi.org/simple" }
