Skip to content

Commit 6b6babd

Browse files
committed
refactor: unify monorepo structure (ADR-0009)
Rename Layer 1 from shared-utils to utils, collapse per-project AGENTS.md to a single root contract, and lock in the unified project shape across the workspace. Layer 1 rename - Folder: projects/shared-utils/ -> projects/utils/ - Distribution: llm-patch-shared -> llm-patch-utils (0.1.0 -> 0.2.0) - Import package: llm_patch_shared -> llm_patch_utils - All 26 .py source files updated; engine + wiki-agent pyproject deps switched to llm-patch-utils. AGENTS contract - Deleted projects/{llm-patch,utils,wiki-agent}/AGENTS.md. - Rewrote root AGENTS.md as the single agent contract. - Added .github/instructions/utils-boundary.instructions.md with applyTo: projects/utils/** preserving the stdlib-only rule. - Updated engine-boundary, usecase-boundary, python-style instructions. Tooling - pyproject.toml: [tool.uv.sources], isort known-first-party. - .pre-commit-config.yaml: mypy-shared-utils -> mypy-utils. - .github/workflows/{ci,release}.yml: matrix + tag glob updates. - .github/pull_request_template.md: dist label + AGENTS reference. - tools/check_layering.py: LAYERS + PROJECT_PACKAGE map updated. - tools/scaffold_project.py: stops emitting per-project AGENTS.md; uses llm-patch-utils dependency. - Makefile: test-shared -> test-utils. Documentation - SPEC.md: layered-architecture diagram, R-1.3/R-1.4 wording, naming conventions, glossary, new section 1.1 Project Shape, section 9 rewritten to drop AGENTS.md from scaffold artifacts. - README.md: workspace layout + project table + adding-a-use-case. - ADR-0009: full MADR record of the rename + AGENTS collapse. - ADR-0001/0002/0004/0005: status callouts referencing ADR-0009; historical bodies preserved by convention. - docs/EXTENDING.md, docs/REGISTRY_PROTOCOL.md, projects/wiki-agent/README.md: prose updates. - projects/utils/{README,CHANGELOG}.md updated; CHANGELOG records the breaking rename in [0.2.0]. - docs/adr/README.md index: added ADR-0008 + ADR-0009; retitled ADR-0005. Verification - python tools/check_layering.py -> OK - engine: 464 passed, 12 skipped - utils: 2 passed - wiki-agent: 46 passed - Get-ChildItem -Recurse -Filter AGENTS.md -> exactly 1 (root) No behavioural changes. Public engine API unchanged.
1 parent 28d0e3d commit 6b6babd

64 files changed

Lines changed: 411 additions & 345 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/instructions/engine-boundary.instructions.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
applyTo: "projects/llm-patch/**"
3-
description: "Engine boundary rules: no imports from use-cases; preserve public API; preserve test baseline 216 passed / 3 skipped."
3+
description: "Engine boundary rules: no imports from use-cases; preserve public API; preserve test baseline 464 passed / 12 skipped."
44
---
55

66
# Engine Boundary Rules
@@ -14,15 +14,16 @@ implement the engine layer of the architecture in
1414

1515
- **Do not import** from `llm_patch_wiki_agent` or any other use-case
1616
package. Dependency direction is one-way (use-cases → engine).
17-
- **Do not import** from `llm_patch_shared` until that dependency is
18-
explicitly added via ADR. Today the engine has no shared-utils dep.
17+
- **May import** from `llm_patch_utils` for shared error types only
18+
(per [ADR-0005](../../docs/adr/0005-engine-shared-errors.md)). Any
19+
broader engine usage of utils helpers requires a new ADR.
1920
- **Do not edit** existing ABCs in `core/interfaces.py` to add a new
2021
capability. Add a new ABC or a new Strategy implementation instead
2122
(Open/Closed).
2223
- **Preserve the public API**: anything currently re-exported from
2324
`src/llm_patch/__init__.py` stays re-exported (additions OK, removals
2425
require a major bump + ADR + deprecation).
25-
- **Preserve the test baseline**: `216 passed, 3 skipped`. Any PR that
26+
- **Preserve the test baseline**: `464 passed, 12 skipped`. Any PR that
2627
changes the count must justify the change in its description.
2728

2829
## When Adding a New Source / Generator / Storage / Provider / Runtime

.github/instructions/python-style.instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ from [SPEC.md](../../SPEC.md). Where this file and `SPEC.md` disagree,
4040

4141
## Errors
4242

43-
- Derive new exception types from `llm_patch_shared.errors.LlmPatchError`
43+
- Derive new exception types from `llm_patch_utils.errors.LlmPatchError`
4444
(or one of its subclasses). Never raise bare `Exception`.
4545
- Catch the narrowest exception possible. Don't swallow exceptions
4646
silently — log or re-raise.

.github/instructions/usecase-boundary.instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ implement the use-case layer of the architecture in
3333
## Allowed Runtime Dependencies
3434

3535
- `llm-patch` (workspace).
36-
- `llm-patch-shared` (workspace).
36+
- `llm-patch-utils` (workspace).
3737
- `click>=8.0`.
3838
- Anything else requires an ADR.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
applyTo: "projects/utils/**"
3+
description: "Utils boundary rules: stdlib-only; no imports from engine or use-cases; new runtime deps require an ADR."
4+
---
5+
6+
# Utils Boundary Rules — `llm-patch-utils`
7+
8+
These rules apply to every file under `projects/utils/`. They implement
9+
Layer 1 (Utilities) of the architecture in
10+
[SPEC.md §1](../../SPEC.md#1-architectural-layering),
11+
[ADR-0002](../../docs/adr/0002-layered-architecture.md), and
12+
[ADR-0009](../../docs/adr/0009-monorepo-structural-unification.md).
13+
14+
## Hard Rules
15+
16+
- **Stdlib only**. Adding any third-party runtime dependency requires
17+
an ADR.
18+
- **Never import** from `llm_patch` or any `llm_patch_<usecase>`
19+
package. Dependencies flow downward only (utils ← engine ← use-cases).
20+
- **No domain logic, no I/O at import time, no network**. This package
21+
hosts genuinely cross-cutting primitives only (logging adapters,
22+
config helpers, telemetry hooks, common error types).
23+
- **Public API is sacred**: anything re-exported from
24+
`src/llm_patch_utils/__init__.py` is part of the published surface.
25+
Removing or renaming a public symbol requires a major version bump,
26+
an ADR, and a deprecation cycle.
27+
28+
## When Adding a New Symbol
29+
30+
1. Confirm two or more downstream projects actually need it. If only
31+
one needs it, keep the helper inside that project instead.
32+
2. Add a unit test in `tests/`.
33+
3. Re-export the symbol from `src/llm_patch_utils/__init__.py` and add
34+
it to `__all__`.
35+
4. Bump the version in `pyproject.toml` per SemVer and add a
36+
`[Unreleased]` entry to `CHANGELOG.md`.
37+
38+
## Test
39+
40+
```pwsh
41+
uv run --package llm-patch-utils pytest -q
42+
```

.github/pull_request_template.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!--
22
Thanks for contributing! Please confirm the items below before requesting review.
3-
See SPEC.md and the per-project AGENTS.md for the full rules.
3+
See SPEC.md and the root AGENTS.md for the full rules.
44
-->
55

66
## What & Why
@@ -10,13 +10,13 @@ See SPEC.md and the per-project AGENTS.md for the full rules.
1010
## Affected Project(s)
1111

1212
- [ ] `llm-patch` (engine)
13-
- [ ] `llm-patch-shared`
13+
- [ ] `llm-patch-utils`
1414
- [ ] `llm-patch-wiki-agent`
1515
- [ ] tooling / docs / CI only
1616

1717
## Checklist
1818

19-
- [ ] Read the relevant `AGENTS.md` (root + per-project).
19+
- [ ] Read the root [AGENTS.md](../AGENTS.md) and the relevant `.github/instructions/*.instructions.md`.
2020
- [ ] Tests added/updated; **engine baseline preserved** (or change justified below).
2121
- [ ] `make check` passes locally (`lint + typecheck + check-layering + test`).
2222
- [ ] Public API change? → updated `__init__.py` `__all__`, `CHANGELOG.md`, and bumped version per SemVer.

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ jobs:
3131
- name: Mypy (engine)
3232
working-directory: projects/llm-patch
3333
run: uv run mypy src
34-
- name: Mypy (shared-utils)
35-
working-directory: projects/shared-utils
34+
- name: Mypy (utils)
35+
working-directory: projects/utils
3636
run: uv run mypy src
3737
- name: Mypy (wiki-agent)
3838
working-directory: projects/wiki-agent
@@ -47,7 +47,7 @@ jobs:
4747
python: ["3.11", "3.12"]
4848
project:
4949
- llm-patch
50-
- llm-patch-shared
50+
- llm-patch-utils
5151
- llm-patch-wiki-agent
5252
steps:
5353
- uses: actions/checkout@v4
@@ -63,8 +63,8 @@ jobs:
6363
if [ "${{ matrix.project }}" = "llm-patch" ]; then
6464
cd projects/llm-patch
6565
uv run pytest -q
66-
elif [ "${{ matrix.project }}" = "llm-patch-shared" ]; then
67-
cd projects/shared-utils
66+
elif [ "${{ matrix.project }}" = "llm-patch-utils" ]; then
67+
cd projects/utils
6868
uv run pytest -q
6969
else
7070
cd projects/wiki-agent

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55
push:
66
tags:
77
- "llm-patch-v*"
8-
- "llm-patch-shared-v*"
8+
- "llm-patch-utils-v*"
99
- "llm-patch-wiki-agent-v*"
1010

1111
jobs:

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ repos:
2323
language: system
2424
pass_filenames: false
2525
files: '^projects/llm-patch/.+\.py$'
26-
- id: mypy-shared-utils
27-
name: mypy-shared-utils
28-
entry: uv run --package llm-patch-shared mypy --config-file projects/shared-utils/pyproject.toml projects/shared-utils/src projects/shared-utils/tests
26+
- id: mypy-utils
27+
name: mypy-utils
28+
entry: uv run --package llm-patch-utils mypy --config-file projects/utils/pyproject.toml projects/utils/src projects/utils/tests
2929
language: system
3030
pass_filenames: false
31-
files: '^projects/shared-utils/.+\.py$'
31+
files: '^projects/utils/.+\.py$'
3232
- id: mypy-wiki-agent
3333
name: mypy-wiki-agent
3434
entry: uv run --package llm-patch-wiki-agent mypy --config-file projects/wiki-agent/pyproject.toml projects/wiki-agent/src projects/wiki-agent/tests

AGENTS.md

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
# AGENTS — Root Contract
22

3-
This file is the **entry point** for any agent (human or AI) working in
4-
this repository. It is intentionally short. Authoritative rules live in
5-
[SPEC.md](SPEC.md). Per-project specifics live in each project's own
6-
`AGENTS.md` under [projects/](projects/).
3+
This file is the **single, authoritative agent contract** for the entire
4+
repository. It is intentionally short. Authoritative engineering rules
5+
live in [SPEC.md](SPEC.md). Scoped, machine-loaded rules live under
6+
[.github/instructions/](.github/instructions/) and are applied
7+
automatically by VS Code / Copilot via `applyTo` globs (see ADR-0009).
8+
9+
There are **no per-project `AGENTS.md` files** — the same checklist and
10+
hard rules apply to every project under [projects/](projects/).
711

812
## Repository Shape
913

10-
This is a **uv workspace monorepo**. The structure is:
14+
This is a **uv workspace monorepo** with a unified per-project layout:
1115

1216
```
1317
projects/
1418
llm-patch/ engine — the generic Ingest → Compile → Attach → Use framework
15-
shared-utils/ cross-project, stdlib-only utilities
19+
utils/ cross-project, stdlib-only utilities (llm_patch_utils)
1620
wiki-agent/ first downstream use-case (wiki-specialized agent)
1721
docs/
1822
adr/ Architecture Decision Records (MADR format)
@@ -25,43 +29,70 @@ SPEC.md the engineering specification (binding)
2529
AGENTS.md this file
2630
```
2731

32+
Every `projects/<name>/` follows the same flat layout — see
33+
[SPEC.md §1.1 Project Shape](SPEC.md):
34+
35+
```
36+
projects/<name>/
37+
pyproject.toml # name = "llm-patch[-<usecase>]"
38+
README.md
39+
CHANGELOG.md
40+
src/<import_pkg>/ # llm_patch[_<usecase>]
41+
tests/
42+
```
43+
2844
## Mandatory Pre-Change Checklist
2945

3046
Before changing any file, the agent must:
3147

32-
1. **Read the closest `AGENTS.md`** the per-project file overrides /
33-
refines this root file. If editing a use-case, read the use-case's
34-
`AGENTS.md` and the engine's `AGENTS.md`.
48+
1. **Read this file** and the relevant scoped instructions under
49+
[.github/instructions/](.github/instructions/) (engine boundary,
50+
utils boundary, use-case boundary, python style, tests).
3551
2. **Re-read the relevant section of [SPEC.md](SPEC.md)** — especially
36-
Dependency Direction and Public API Stability.
52+
Dependency Direction (§1) and Public API Stability (§3).
3753
3. **Write or update tests first** — the project follows TDD for new
3854
public API. See SPEC §Testing.
3955
4. **Run `uv run --package <project> pytest -q`** for the affected
4056
project(s) and confirm baselines hold:
41-
- `llm-patch` engine: `216 passed, 3 skipped`
42-
- `llm-patch-shared`, `llm-patch-wiki-agent`: smoke tests pass.
57+
- `llm-patch` engine: `464 passed, 12 skipped`.
58+
- `llm-patch-utils`, `llm-patch-wiki-agent`: smoke tests pass.
4359
5. **Add an ADR** under [docs/adr/](docs/adr/) for any cross-cutting,
4460
architectural, or dependency-direction-affecting decision. Use
4561
[docs/adr/0000-template.md](docs/adr/0000-template.md).
4662

4763
## Hard Rules (do not violate without an ADR)
4864

49-
- **Dependency direction is one-way**: use-cases → engine → shared-utils.
65+
- **Dependency direction is one-way**: use-cases → engine → utils.
5066
No reverse imports. Enforced by [tools/check_layering.py](tools/check_layering.py).
5167
- **Public API is sacred**: only symbols re-exported from a project's
5268
top-level `__init__.py` are public. Use-cases must consume only the
5369
public API of the engine.
5470
- **No behavior changes alongside structural changes** in the same PR.
5571
- **No module-level side effects** (no I/O, no network) at import time.
72+
- **No per-project `AGENTS.md`**: scoped rules belong in
73+
`.github/instructions/*.instructions.md` with an `applyTo` glob.
74+
75+
## Adding a New Use-Case Project
76+
77+
```pwsh
78+
uv run python tools/scaffold_project.py <name>
79+
```
80+
81+
This materializes the unified layout above. The new project consumes
82+
the engine via its public API and may depend on `llm-patch-utils`. See
83+
[SPEC.md §9](SPEC.md) and use [projects/wiki-agent/](projects/wiki-agent/)
84+
as the reference implementation.
5685

5786
## Where to Look for What
5887

5988
| If you want to… | Read… |
6089
|---|---|
6190
| Understand the system architecture | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) |
6291
| Understand the engineering rules | [SPEC.md](SPEC.md) |
63-
| Add a new use-case project | [tools/scaffold_project.py](tools/scaffold_project.py) + this file |
64-
| Change the engine | [projects/llm-patch/AGENTS.md](projects/llm-patch/AGENTS.md) |
65-
| Change shared utilities | [projects/shared-utils/AGENTS.md](projects/shared-utils/AGENTS.md) |
66-
| Change the wiki agent | [projects/wiki-agent/AGENTS.md](projects/wiki-agent/AGENTS.md) |
92+
| Add a new use-case project | [tools/scaffold_project.py](tools/scaffold_project.py) + [SPEC.md §9](SPEC.md) |
93+
| Change the engine | [.github/instructions/engine-boundary.instructions.md](.github/instructions/engine-boundary.instructions.md) |
94+
| Change utilities | [.github/instructions/utils-boundary.instructions.md](.github/instructions/utils-boundary.instructions.md) |
95+
| Change a use-case | [.github/instructions/usecase-boundary.instructions.md](.github/instructions/usecase-boundary.instructions.md) |
96+
| Write Python | [.github/instructions/python-style.instructions.md](.github/instructions/python-style.instructions.md) |
97+
| Write tests | [.github/instructions/tests.instructions.md](.github/instructions/tests.instructions.md) |
6798
| See past architectural decisions | [docs/adr/README.md](docs/adr/README.md) |

Makefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: help sync test test-engine test-shared test-wiki-agent lint typecheck check check-layering check-coverage build clean adr
1+
.PHONY: help sync test test-engine test-utils test-wiki-agent lint typecheck check check-layering check-coverage build clean adr
22

33
# ─────────────────────────────────────────────────────────────
44
# llm-patch monorepo — workspace fan-out commands
@@ -22,13 +22,13 @@ sync: ## Sync the entire workspace
2222
test-engine: ## Run engine tests
2323
cd projects/llm-patch && $(UV) run pytest -q
2424

25-
test-shared: ## Run shared-utils smoke tests
26-
cd projects/shared-utils && $(UV) run pytest -q
25+
test-utils: ## Run utils smoke tests
26+
cd projects/utils && $(UV) run pytest -q
2727

2828
test-wiki-agent: ## Run wiki-agent smoke tests
2929
cd projects/wiki-agent && $(UV) run pytest -q
3030

31-
test: test-engine test-shared test-wiki-agent ## Run tests for every workspace member
31+
test: test-engine test-utils test-wiki-agent ## Run tests for every workspace member
3232

3333
# ── Quality ─────────────────────────────────────────────────
3434

@@ -37,7 +37,7 @@ lint: ## Lint the entire workspace
3737

3838
typecheck: ## Mypy strict for every project
3939
cd projects/llm-patch && $(UV) run mypy src
40-
cd projects/shared-utils && $(UV) run mypy src
40+
cd projects/utils && $(UV) run mypy src
4141
cd projects/wiki-agent && $(UV) run mypy src
4242

4343
check-layering: ## Architectural fitness check (ADR-0002)
@@ -53,7 +53,7 @@ check: lint typecheck check-layering test check-coverage ## Lint + typecheck + l
5353

5454
build: ## Build distributions for every project
5555
cd projects/llm-patch && $(UV) build
56-
cd projects/shared-utils && $(UV) build
56+
cd projects/utils && $(UV) build
5757
cd projects/wiki-agent && $(UV) build
5858

5959
# ── ADR helper ──────────────────────────────────────────────

0 commit comments

Comments
 (0)