Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
"name": "python-engineering-standards",
"version": "0.6.0",
"version": "1.0.0",
"description": "Internal marketplace for the Python Engineering Harness, including MCP governance.",
"owner": {
"name": "Engineering Team"
Expand All @@ -10,7 +10,7 @@
{
"name": "python-engineering-harness",
"description": "Python engineering agents, skills, safety hooks, MCP governance, and output style.",
"version": "0.6.0",
"version": "1.0.0",
"author": {
"name": "Engineering Team"
},
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/harness-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,33 @@ permissions:
contents: read

jobs:
repository-quality:
runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- name: Check out repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7

- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: "3.12"

- name: Install uv
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
with:
version: "0.11.28"

- name: Verify lockfile is up to date
run: uv lock --check

- name: Install repository dependencies
run: uv sync --frozen --all-groups

- name: Run complete repository quality gate
run: uv run python scripts/quality_gate.py

test:
strategy:
fail-fast: false
Expand Down Expand Up @@ -50,6 +77,9 @@ jobs:
- name: Reject whitespace errors
run: git diff --check

- name: Check sibling-harness parity manifest
run: python scripts/parity_check.py

generated-profiles:
strategy:
fail-fast: false
Expand Down
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,33 @@
# Changelog

All notable changes to the harness are documented here. Harness, development package, and plugin
versions are independent; see `docs/VERSIONING.md`.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the harness uses
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## 1.0.0 - 2026-07-19

First tagged release. Consolidates the loop foundation below and closes the structural-parity gap
with the sibling `codex-python-engineering-harness` (which consumes releases by tag).

### Added

- Repository-level `pyproject.toml`, `uv.lock`, and `scripts/quality_gate.py`, so the harness runs
the same deterministic gate it installs into generated projects (Ruff, format, Mypy, Bandit,
pip-audit, regression tests, governance gate, and the full profile × governance render matrix)
on its own code. A new `repository-quality` CI job invokes it.
- `docs/ARCHITECTURE.md` (Claude-native surface decisions, profile and governance composition,
and the documented Langfuse-vs-OpenTelemetry divergence from the Codex sibling) and
`docs/VERSIONING.md` (independent harness, development package, and plugin lifecycles).
- `scripts/parity_check.py` with `parity-manifest.json` and `parity-exceptions.json`: a
deterministic check, shared with the Codex sibling, that fails CI when a parity-required
artifact is missing and is not declared as an intentional divergence. Wired into CI.
- A documented language policy in `CONTRIBUTING.md` (English canonical; pt-BR required for
`docs/LOOPS`, `docs/UPGRADING`, and `docs/ENTERPRISE_ROLLOUT`).

- Phase 0-1 (report-only) Evidence-Gated Engineering Loop foundation, see `docs/LOOPS.md` /
`docs/LOOPS.pt-BR.md`:
- `.loop/**` and `scripts/loop_*` are now denylisted for agent writes in
Expand All @@ -27,6 +51,10 @@
tests prove that manual tampering is rejected. The earlier `75a63eef...` integration described
below was an intermediate pre-release state and is superseded by this published bundle.

### Changed

- Harness, plugin, and marketplace versions promoted from 0.6.0 to 1.0.0.

### Fixed

- Re-vendored `_vendor_loop_schemas/{__init__,models,validate_contract}.py` from
Expand Down
17 changes: 17 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ only when evaluation order requires it.
Prefer changing the canonical template first, then port the equivalent plugin change. The regression
suite verifies that duplicated Python scripts remain identical.

## Language policy

English is the canonical language for all documentation. The following documents must also ship a
`.pt-BR.md` sibling, updated in the same change: `docs/LOOPS.md`, `docs/UPGRADING.md`, and
`docs/ENTERPRISE_ROLLOUT.md`. Other documents may be translated opportunistically, but a stale
translation is worse than none: if you cannot update the pair, say so in the pull request. The
sibling `codex-python-engineering-harness` follows the same policy so both harnesses keep the same
language matrix.

## Sibling-harness parity

This harness and `codex-python-engineering-harness` share a parity manifest
(`parity-manifest.json`, byte-identical in both repositories) checked in CI by
`scripts/parity_check.py`. When adding or removing a parity-relevant artifact, update the manifest
in both repositories in the same change, or declare an intentional divergence with a reason in
this repository's `parity-exceptions.json`.

## Release checklist

- Keep changes focused and update tests for behavioral changes.
Expand Down
11 changes: 6 additions & 5 deletions bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""Render, upgrade, or check the Python engineering harness."""

import argparse
import contextlib
import hashlib
import json
import keyword
Expand All @@ -16,7 +17,7 @@
from pathlib import Path
from typing import Any

HARNESS_VERSION = "0.6.0"
HARNESS_VERSION = "1.0.0"
DEFAULT_BRANCH = "main"
PROFILES = ("service", "library", "workspace")
GOVERNANCE_CATALOG_VERSION = "2026.1"
Expand Down Expand Up @@ -225,10 +226,8 @@ def sha256(data: bytes) -> str:

def _render_source(source: Path, values: dict[str, str]) -> RenderedFile:
data = source.read_bytes()
try:
with contextlib.suppress(UnicodeDecodeError):
data = render_text(data.decode("utf-8"), values).encode("utf-8")
except UnicodeDecodeError:
pass
return RenderedFile(data=data, mode=stat.S_IMODE(source.stat().st_mode))


Expand Down Expand Up @@ -734,7 +733,9 @@ def main(argv: list[str] | None = None) -> int:
print("Review generated conflict files:")
for conflict in conflicts:
print(f" - {conflict.relative_to(target)}")
print("Next: review AGENTS.md, .claude/settings.json, docs/MCP.md, and governance/ when enabled")
print(
"Next: review AGENTS.md, .claude/settings.json, docs/MCP.md, and governance/ when enabled"
)
return 0


Expand Down
60 changes: 60 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Architecture decisions

## Claude Code-native surfaces

- `CLAUDE.md` is the always-loaded repository contract; `AGENTS.md` carries the shared
cross-platform engineering contract so a generated project remains legible to non-Claude
tooling. Generated profile overlays replace them only when commands and layout differ.
- Detailed guidance lives in path-scoped rules under `.claude/rules/`, loaded only when relevant
files are touched, keeping the always-loaded contract small.
- Specialized subagents live in `.claude/agents/`; project skills in `.claude/skills/`.
Distributable copies of both live at the plugin root (`plugin/python-engineering-harness/`).
- Hook scripts stay in `.claude/hooks/` so commands can resolve them from the Git root when
Claude Code starts in a subdirectory. `.claude/settings.json` is the only project hook and
permission representation at that layer.
- The plugin uses the documented default `hooks/hooks.json`; its commands resolve scripts through
`CLAUDE_PLUGIN_ROOT` and its manifest does not duplicate the default hook path.
- The repo marketplace is `.claude-plugin/marketplace.json` and points to
`./plugin/python-engineering-harness` relative to the marketplace root.

## Profile composition

`template/` is the service-compatible base. `library` removes service/container/observability
pieces and overlays library metadata. `workspace` removes all artificial package/test trees and
overlays a virtual uv root. Profiles are generator choices, never monorepo packages in this repo.

The `library` profile intentionally has no `.github/` overlay: it inherits the template's
workflow unchanged, because the project-owned `scripts/quality_gate.py` reads its roots from
`pyproject.toml` and needs no profile-specific CI. The `workspace` profile overrides the workflow
because member discovery changes the commands. (The Codex sibling ships a `library` CI overlay
because its template workflow differs; this asymmetry is declared in `parity-exceptions.json`.)

## Governance composition

Technical profiles and governance are orthogonal. `--governance-profile` selects capability-based
controls while repeatable `--governance-overlay` options add regulatory requirements. `none` is the
default to keep upgrades compatible. The bootstrap snapshots the canonical catalog, schemas, and
composed selection into each governed project; generated projects never depend on this source
repository at runtime.

The catalog uses original control descriptions and many-to-many support mappings. It does not copy
licensed standards or assert compliance. Project-owned inventories, risks, assessments, and
exceptions remain separate from bootstrap-owned snapshots.

## Controls

Lifecycle hooks provide defense in depth for command safety, sensitive paths, secret scanning,
MCP mutation classification, and changed-file formatting. They do not replace Claude Code
permission policy, sandboxing, CI, or human review. Hard enforcement requires managed policy,
credentials, and repository protection outside the agent's reach; hooks stop accidents and raise
the cost of drift.

## Observability divergence from the Codex sibling

The generated service's LLM-tracing starter uses Langfuse metadata-only tracing (`--extra
tracing`), while the Codex sibling ships an OpenTelemetry adapter (`--extra observability`). This
is an intentional platform-level decision, not drift: Codex exposes native OpenTelemetry export,
so its harness builds on that; Claude Code does not, so this harness offers an opt-in,
allowlisted-metadata Langfuse integration with backend-failure isolation instead. Both starters
collect metadata only — never prompts, completions, file contents, or command output. The
divergence is declared in `parity-exceptions.json`.
25 changes: 25 additions & 0 deletions docs/VERSIONING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Versioning model

This repository contains three independently versioned artifacts:

| Artifact | Current version source | Meaning |
|---|---|---|
| Harness generator | `bootstrap.py` (`HARNESS_VERSION`) | Version recorded in generated project metadata (`.harness.json`) and used for upgrade and drift checks. |
| Development package | root `pyproject.toml` | Local tooling package for developing and validating this repository; it is not the generated project's version. |
| Claude Code plugin | `plugin/python-engineering-harness/.claude-plugin/plugin.json` | Installable plugin release containing reusable agents, skills, hooks, and output style. The repository marketplace (`.claude-plugin/marketplace.json`) tracks the plugin version it distributes. |

Versions do not need to match. A generator release can change templates without changing the
plugin, and a plugin release can improve workflows without changing generated files. Each artifact
uses semantic versioning within its own lifecycle.

The generated project's version is separately owned by that project and starts at `0.1.0` by
default. Upgrading the harness must never overwrite that application or library version.

Release notes must identify which artifact changed. Compatibility-impacting changes to generated
files require a harness version change and upgrade instructions. Plugin-only changes require a
plugin version change. The root development package changes only when its packaging contract
changes.

Git tags (`vX.Y.Z`) follow the harness generator version. The sibling
`codex-python-engineering-harness` and any cross-harness tooling consume this repository by
release tag, so every compatibility-impacting generator change must be tagged.
13 changes: 13 additions & 0 deletions parity-exceptions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": 1,
"exceptions": [
{
"id": "profile-library-ci-overlay",
"reason": "The library profile inherits the template's .github/workflows/quality.yml unchanged; the Codex sibling ships a profiles/library CI overlay because its template workflow differs. Documented in docs/ARCHITECTURE.md."
},
{
"id": "observability-adapter",
"reason": "LLM tracing starter is Langfuse metadata-only (--extra tracing); the Codex sibling ships an OpenTelemetry adapter because Codex exposes native OTel export. Documented in docs/ARCHITECTURE.md."
}
]
}
49 changes: 49 additions & 0 deletions parity-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"version": 1,
"description": "Family-independent artifacts both Python engineering harnesses must ship. Family-specific artifacts (hooks, plugin, and marketplace manifests) are derived at runtime by scripts/parity_check.py. Keep this file byte-identical in codex-python-engineering-harness and claude-python-engineering-harness; update both repositories in the same change. Intentional divergences are declared per-repository in parity-exceptions.json.",
"artifacts": [
{"id": "readme", "path": "README.md"},
{"id": "changelog", "path": "CHANGELOG.md"},
{"id": "license", "path": "LICENSE"},
{"id": "contributing", "path": "CONTRIBUTING.md"},
{"id": "security-policy", "path": "SECURITY.md"},
{"id": "support-policy", "path": "SUPPORT.md"},
{"id": "code-of-conduct", "path": "CODE_OF_CONDUCT.md"},
{"id": "validation-record", "path": "VALIDATION.md"},
{"id": "sources", "path": "SOURCES.md"},
{"id": "doc-architecture", "path": "docs/ARCHITECTURE.md"},
{"id": "doc-versioning", "path": "docs/VERSIONING.md"},
{"id": "doc-loops", "path": "docs/LOOPS.md"},
{"id": "doc-loops-pt-br", "path": "docs/LOOPS.pt-BR.md"},
{"id": "doc-upgrading", "path": "docs/UPGRADING.md"},
{"id": "doc-upgrading-pt-br", "path": "docs/UPGRADING.pt-BR.md"},
{"id": "doc-evaluation", "path": "docs/EVALUATION.md"},
{"id": "doc-enterprise-rollout", "path": "docs/ENTERPRISE_ROLLOUT.md"},
{"id": "doc-enterprise-rollout-pt-br", "path": "docs/ENTERPRISE_ROLLOUT.pt-BR.md"},
{"id": "root-pyproject", "path": "pyproject.toml"},
{"id": "root-lockfile", "path": "uv.lock"},
{"id": "bootstrap", "path": "bootstrap.py"},
{"id": "repo-quality-gate", "path": "scripts/quality_gate.py"},
{"id": "loop-self-evaluation", "path": "scripts/loop_self_evaluation.py"},
{"id": "parity-script", "path": "scripts/parity_check.py"},
{"id": "parity-exceptions", "path": "parity-exceptions.json"},
{"id": "tests-harness", "path": "tests/test_harness.py"},
{"id": "tests-loop-vendor", "path": "tests/test_loop_schema_vendor.py"},
{"id": "ci-harness-quality", "path": ".github/workflows/harness-quality.yml"},
{"id": "ci-loop-self-evaluation", "path": ".github/workflows/loop-self-evaluation.yml"},
{"id": "governance-readme", "path": "governance/README.md"},
{"id": "governance-catalog", "path": "governance/catalog/controls.json"},
{"id": "governance-overlay-dora", "path": "governance/overlays/dora.json"},
{"id": "governance-overlay-iso-42001", "path": "governance/overlays/iso-iec-42001.json"},
{"id": "governance-overlay-800-53", "path": "governance/overlays/nist-sp-800-53.json"},
{"id": "template-pyproject", "path": "template/pyproject.toml"},
{"id": "template-quality-gate", "path": "template/scripts/quality_gate.py"},
{"id": "template-validate-architecture", "path": "template/scripts/validate_architecture.py"},
{"id": "template-validate-mcp", "path": "template/scripts/validate_mcp_config.py"},
{"id": "template-governance-gate", "path": "template/scripts/governance_gate.py"},
{"id": "template-loop-contracts", "path": "template/scripts/validate_loop_contracts.py"},
{"id": "template-loop-vendor-manifest", "path": "template/scripts/_vendor_loop_schemas/manifest.json"},
{"id": "profile-library-pyproject", "path": "profiles/library/pyproject.toml"},
{"id": "profile-workspace-pyproject", "path": "profiles/workspace/pyproject.toml"}
]
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "python-engineering-harness",
"displayName": "Python Engineering Harness",
"version": "0.6.0",
"version": "1.0.0",
"description": "Reusable Python engineering agents, skills, safety hooks, MCP governance, and output style for Claude Code.",
"author": {
"name": "Engineering Team"
Expand Down
Loading
Loading