sherparc 0.8.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. sherparc-0.8.1/LICENSE +161 -0
  2. sherparc-0.8.1/PKG-INFO +14 -0
  3. sherparc-0.8.1/README.md +289 -0
  4. sherparc-0.8.1/pyproject.toml +37 -0
  5. sherparc-0.8.1/setup.cfg +4 -0
  6. sherparc-0.8.1/src/sherpa/__init__.py +1 -0
  7. sherparc-0.8.1/src/sherpa/apply/__init__.py +614 -0
  8. sherparc-0.8.1/src/sherpa/apply/adopt.py +579 -0
  9. sherparc-0.8.1/src/sherpa/apply/assets/sherpa-outcome.py +258 -0
  10. sherparc-0.8.1/src/sherpa/apply/render.py +701 -0
  11. sherparc-0.8.1/src/sherpa/apply/state.py +129 -0
  12. sherparc-0.8.1/src/sherpa/apply/status.py +173 -0
  13. sherparc-0.8.1/src/sherpa/atomic.py +25 -0
  14. sherparc-0.8.1/src/sherpa/check.py +383 -0
  15. sherparc-0.8.1/src/sherpa/cli.py +463 -0
  16. sherparc-0.8.1/src/sherpa/config.py +130 -0
  17. sherparc-0.8.1/src/sherpa/doctor.py +231 -0
  18. sherparc-0.8.1/src/sherpa/gitinfo.py +144 -0
  19. sherparc-0.8.1/src/sherpa/model.py +229 -0
  20. sherparc-0.8.1/src/sherpa/plan/__init__.py +122 -0
  21. sherparc-0.8.1/src/sherpa/plan/rules.py +436 -0
  22. sherparc-0.8.1/src/sherpa/plan/yamlio.py +262 -0
  23. sherparc-0.8.1/src/sherpa/scan/__init__.py +70 -0
  24. sherparc-0.8.1/src/sherpa/scan/generators.py +370 -0
  25. sherparc-0.8.1/src/sherpa/scan/t0_git.py +256 -0
  26. sherparc-0.8.1/src/sherpa/scan/t1_modules.py +606 -0
  27. sherparc-0.8.1/src/sherpa/schema.py +86 -0
  28. sherparc-0.8.1/src/sherpa/schemas/codebase-model.schema.json +619 -0
  29. sherparc-0.8.1/src/sherpa/schemas/harness-plan.schema.json +171 -0
  30. sherparc-0.8.1/src/sherpa/schemas/harness-state.schema.json +37 -0
  31. sherparc-0.8.1/src/sherpa/update.py +327 -0
  32. sherparc-0.8.1/src/sherparc.egg-info/PKG-INFO +14 -0
  33. sherparc-0.8.1/src/sherparc.egg-info/SOURCES.txt +52 -0
  34. sherparc-0.8.1/src/sherparc.egg-info/dependency_links.txt +1 -0
  35. sherparc-0.8.1/src/sherparc.egg-info/entry_points.txt +2 -0
  36. sherparc-0.8.1/src/sherparc.egg-info/requires.txt +7 -0
  37. sherparc-0.8.1/src/sherparc.egg-info/top_level.txt +1 -0
  38. sherparc-0.8.1/tests/test_adopt.py +663 -0
  39. sherparc-0.8.1/tests/test_apply.py +1387 -0
  40. sherparc-0.8.1/tests/test_architecture_docs.py +51 -0
  41. sherparc-0.8.1/tests/test_check.py +287 -0
  42. sherparc-0.8.1/tests/test_cli.py +15 -0
  43. sherparc-0.8.1/tests/test_config.py +24 -0
  44. sherparc-0.8.1/tests/test_doctor.py +218 -0
  45. sherparc-0.8.1/tests/test_generators.py +137 -0
  46. sherparc-0.8.1/tests/test_gitinfo.py +94 -0
  47. sherparc-0.8.1/tests/test_plan.py +698 -0
  48. sherparc-0.8.1/tests/test_remove.py +178 -0
  49. sherparc-0.8.1/tests/test_render_demo.py +59 -0
  50. sherparc-0.8.1/tests/test_scan.py +171 -0
  51. sherparc-0.8.1/tests/test_schema.py +167 -0
  52. sherparc-0.8.1/tests/test_t0_git.py +172 -0
  53. sherparc-0.8.1/tests/test_t1_modules.py +521 -0
  54. sherparc-0.8.1/tests/test_update.py +500 -0
sherparc-0.8.1/LICENSE ADDED
@@ -0,0 +1,161 @@
1
+ Sherpa — Copyright (c) 2026 Andrei Chirila
2
+
3
+ Required Notice: Copyright Andrei Chirila (https://github.com/sherparc/Sherpa)
4
+
5
+ Sherpa is licensed under the PolyForm Small Business License 1.0.0 or the
6
+ PolyForm Noncommercial License 1.0.0, at your option
7
+ (SPDX: PolyForm-Small-Business-1.0.0 OR PolyForm-Noncommercial-1.0.0).
8
+ Both texts follow below, unchanged. In short: free for personal use, for
9
+ noncommercial organisations, and for companies with fewer than 100 people and
10
+ under USD 1M revenue; a company above those limits needs a commercial licence
11
+ — a.chirila87@gmail.com. Reasoning: docs/adr/0051-public-release-polyform-small-business-or-noncommercial.md.
12
+
13
+ Output exception (an additional permission granted by the licensor): files
14
+ that Sherpa generates in your repository — plans, state files, owner docs,
15
+ agent and skill definitions, and any other output of `sherpa plan` or
16
+ `sherpa apply` — belong to you. They carry no obligation under either licence,
17
+ regardless of how you obtained Sherpa.
18
+
19
+ ================================================================================
20
+
21
+ # PolyForm Small Business License 1.0.0
22
+
23
+ <https://polyformproject.org/licenses/small-business/1.0.0>
24
+
25
+ ## Acceptance
26
+
27
+ In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
28
+
29
+ ## Copyright License
30
+
31
+ The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
32
+
33
+ ## Distribution License
34
+
35
+ The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
36
+
37
+ ## Notices
38
+
39
+ You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
40
+
41
+ > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
42
+
43
+ ## Changes and New Works License
44
+
45
+ The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
46
+
47
+ ## Patent License
48
+
49
+ The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
50
+
51
+ ## Fair Use
52
+
53
+ You may have "fair use" rights for the software under the law. These terms do not limit them.
54
+
55
+ ## Small Business
56
+
57
+ Use of the software for the benefit of your company is use for a permitted purpose if your company has fewer than 100 total individuals working as employees and independent contractors, and less than 1,000,000 USD (2019) total revenue in the prior tax year. Adjust this revenue threshold for inflation according to the United States Bureau of Labor Statistics' consumer price index for all urban consumers, U.S. city average, for all items, not seasonally adjusted, with 1982–1984=100 reference base.
58
+
59
+ ## No Other Rights
60
+
61
+ These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
62
+
63
+ ## Patent Defense
64
+
65
+ If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
66
+
67
+ ## Violations
68
+
69
+ The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
70
+
71
+ ## No Liability
72
+
73
+ ***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
74
+
75
+ ## Definitions
76
+
77
+ The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
78
+
79
+ **You** refers to the individual or entity agreeing to these terms.
80
+
81
+ **Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
82
+
83
+ **Your licenses** are all the licenses granted to you for the software under these terms.
84
+
85
+ **Use** means anything you do with the software requiring one of your licenses.
86
+
87
+ ================================================================================
88
+
89
+ # PolyForm Noncommercial License 1.0.0
90
+
91
+ <https://polyformproject.org/licenses/noncommercial/1.0.0>
92
+
93
+ ## Acceptance
94
+
95
+ In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
96
+
97
+ ## Copyright License
98
+
99
+ The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
100
+
101
+ ## Distribution License
102
+
103
+ The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
104
+
105
+ ## Notices
106
+
107
+ You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
108
+
109
+ > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
110
+
111
+ ## Changes and New Works License
112
+
113
+ The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
114
+
115
+ ## Patent License
116
+
117
+ The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
118
+
119
+ ## Noncommercial Purposes
120
+
121
+ Any noncommercial purpose is a permitted purpose.
122
+
123
+ ## Personal Uses
124
+
125
+ Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
126
+
127
+ ## Noncommercial Organizations
128
+
129
+ Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
130
+
131
+ ## Fair Use
132
+
133
+ You may have "fair use" rights for the software under the law. These terms do not limit them.
134
+
135
+ ## No Other Rights
136
+
137
+ These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
138
+
139
+ ## Patent Defense
140
+
141
+ If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
142
+
143
+ ## Violations
144
+
145
+ The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
146
+
147
+ ## No Liability
148
+
149
+ ***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
150
+
151
+ ## Definitions
152
+
153
+ The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
154
+
155
+ **You** refers to the individual or entity agreeing to these terms.
156
+
157
+ **Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
158
+
159
+ **Your licenses** are all the licenses granted to you for the software under these terms.
160
+
161
+ **Use** means anything you do with the software requiring one of your licenses.
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.4
2
+ Name: sherparc
3
+ Version: 0.8.1
4
+ Summary: Generic AI-harness generator: scan the codebase, plan owner docs, agents and skills, create them after approval.
5
+ License-Expression: PolyForm-Small-Business-1.0.0 OR PolyForm-Noncommercial-1.0.0
6
+ Requires-Python: >=3.12
7
+ License-File: LICENSE
8
+ Requires-Dist: pyyaml>=6
9
+ Provides-Extra: dev
10
+ Requires-Dist: pytest>=8; extra == "dev"
11
+ Requires-Dist: pytest-cov>=5; extra == "dev"
12
+ Requires-Dist: jsonschema>=4; extra == "dev"
13
+ Requires-Dist: ruff>=0.6; extra == "dev"
14
+ Dynamic: license-file
@@ -0,0 +1,289 @@
1
+ <div align="center">
2
+
3
+ # Sherpa
4
+
5
+ <img src="assets/sherpa-mark.png" width="132" alt="Sherpa">
6
+
7
+ **Your repository grows. Your AI agents lose the plot.**
8
+
9
+ Sherpa analyses your codebase deterministically (like CodeScene) and plans the knowledge architecture for AI assistants from it (like Terraform): owner docs, specialised agents, skills, librarians, evals. You review the plan — Sherpa sets it up after your approval.
10
+
11
+ Sherpa reads your git history and gives a reason for every proposal — and for every no. It writes into the repository you already have, for the runtimes you already use: Claude Code natively, every `AGENTS.md` reader (Codex, Cursor, Copilot, Gemini CLI, OpenCode, Hermes) through one neutral core, one thin adapter per host on the roadmap.
12
+
13
+ [![CI](https://github.com/sherparc/Sherpa/actions/workflows/ci.yml/badge.svg)](https://github.com/sherparc/Sherpa/actions/workflows/ci.yml)
14
+ ![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue)
15
+ ![Status: scan, plan, apply, adopt, doctor live](https://img.shields.io/badge/status-scan%20%2B%20plan%20%2B%20apply%20%2B%20adopt%20%2B%20doctor%20live-brightgreen)
16
+ [![Release](https://img.shields.io/github/v/release/sherparc/Sherpa?include_prereleases&label=release)](https://github.com/sherparc/Sherpa/releases)
17
+
18
+ </div>
19
+
20
+ ---
21
+
22
+ <a href="assets/demo.svg"><img src="assets/demo.svg" alt="sherpa plan on the Sherpa repository itself: five proposals, three reasoned no's, every line with its evidence" width="100%"></a>
23
+
24
+ `sherpa plan .` on this repository — the real output, rendered as an SVG by [scripts/render-demo.py](scripts/render-demo.py) and refreshed with every release. An agent for the whole package was proposed, rejected by hand, and the rejection is kept (`[reject]`); two small modules get a reasoned no with the knob that would change it.
25
+
26
+ ## From repo to AI harness in 60 seconds
27
+
28
+ Live today — real output on a test repo with five Python modules, Django migrations and a test suite
29
+ (`active_repo` in [tests/test_plan.py](tests/test_plan.py), frozen as a [golden](tests/goldens/active-console.txt)):
30
+
31
+ ```console
32
+ $ sherpa plan .
33
+ harness-plan.yaml — 6 proposals, 4 reasoned no's
34
+ + outcome shop mandatory: no harness without an outcome signal (ADR-0008) ✓
35
+ + owner-doc pay 24 commits/90d, 1 dependents ✓ · 40 files ✓
36
+ + owner-doc core 1 commits/90d, 2 dependents ✓ · 3 files ✓
37
+ + agent pay rank 1/4 churn ✓ · 24 commits/90d ✓ · 40 files ✓ · 2 authors ✓
38
+ + test-infra suite 26 commits/90d vs. 24 (pay) ✓
39
+ + skill regenerate-django-migrations svc/pay/pay/migrations · 6 generated files, 1 configs ✓
40
+ - owner-doc web 1 commits/90d, 0 dependents ✓ · 3 files ✗
41
+ - owner-doc old 0 commits/90d, 0 dependents ✗ · 2 files ✗
42
+ - librarian pay rank 1/4 momentum ✓ · 24 commits/30d, 24/90d ✗
43
+ - librarian core rank 2/4 momentum ✓ · 1 commits/30d, 1/90d ✗
44
+ 1 dormant units without owner doc (0 commits/90d, 0 dependents): old — the first commit turns them into a proposal; each is listed above as a no.
45
+ 1 small units without owner doc (< 5 files, 0 dependents): web — listed above as no's; owner_doc_min_files in sherpa.toml [plan] moves the floor, a dependent overrides it.
46
+ not listed, out of reach: 2 units for agent (rank > 1 and < 20 commits/90d), 1 for librarian (rank > 2 and below both floors).
47
+ → .sherpa/harness-plan.yaml
48
+ ```
49
+
50
+ Every line can be recomputed: the rank from the ranking in the plan header, the floors from `sherpa.toml [plan]`.
51
+ The migrations directory gets no agent but a skill with source, config and command — **generated code is
52
+ regenerated, not explained.** Dormant modules and everything out of reach show up in the notes; nothing disappears
53
+ silently.
54
+
55
+ Then `sherpa apply` — dry run first, like `terraform plan` (golden [active-apply-console.txt](tests/goldens/active-apply-console.txt)):
56
+
57
+ ```console
58
+ $ sherpa apply .
59
+ targets: claude, agents-md · home: .agents
60
+ sherpa apply — plan origin/main@5db69c4ddd: 10 entries, 5 selected → 18 files
61
+ + .agents/docs/modules/core.md owner-doc core new
62
+ + .agents/docs/modules/pay.md owner-doc pay new
63
+ + .agents/docs/modules/suite.md test-infra suite new
64
+ + .agents/scripts/sherpa-check.py harness new
65
+ + .agents/skills/regenerate-django-migrations/SKILL.md skill regenerate-django-migrations new
66
+ + .claude/agents/pay.md agent pay new
67
+ + .claude/hooks/sherpa-outcome.py harness new
68
+ + .claude/settings.json harness new
69
+ + .claude/skills/regenerate-django-migrations/SKILL.md skill regenerate-django-migrations new
70
+ + .sherpa/telemetry/.gitignore harness new
71
+ + AGENTS.md harness new
72
+ + CLAUDE.md harness new
73
+ + svc/core/AGENTS.md owner-doc core new
74
+ + svc/core/CLAUDE.md owner-doc core new
75
+ + svc/pay/AGENTS.md owner-doc pay new
76
+ + svc/pay/CLAUDE.md owner-doc pay new
77
+ + tests/suite/AGENTS.md test-infra suite new
78
+ + tests/suite/CLAUDE.md test-infra suite new
79
+ 18 to add, 0 to change, 0 unchanged, 0 skipped.
80
+ apply? [y/N] y
81
+ check: 0 FAIL, 0 WARN
82
+ 18 files written · harness_rev c38498363846 → .sherpa/state.json
83
+ ```
84
+
85
+ The owner doc under `.agents/` gets a facts block from the scanner (path, LOC, commits, authors, dependencies,
86
+ dependents, tests, hotspots — [golden](tests/goldens/active-owner-doc-pay.md)); every module gets a nested
87
+ `AGENTS.md` with its facts ([golden](tests/goldens/active-agents-md-pay.md)) — the file Codex, Cursor, Gemini CLI
88
+ and Copilot load when they work there — and a `CLAUDE.md` that imports it; the Claude agent gets a knowledge
89
+ manifest that points at the owner doc ([golden](tests/goldens/active-agent-pay.md)); the migrations directory
90
+ gets its skill; the outcome hook labels every Claude Code execution with the harness version from day one. Run it again: eighteen `=`, `nothing to do.`
91
+ Sherpa owns only the marked blocks — write anything else into those files, it stays.
92
+
93
+ Already have a harness? `sherpa adopt` takes it into the state without changing a byte — like `terraform import`
94
+ (golden [active-adopt-console.txt](tests/goldens/active-adopt-console.txt)):
95
+
96
+ ```console
97
+ $ sherpa adopt .
98
+ sherpa adopt — home .claude · targets claude: 7 harness files
99
+ a .claude/agents/ops.md agent no unit matches
100
+ a .claude/agents/pay-expert.md agent → agent pay (mentions svc/pay 170×)
101
+ a .claude/docs/modules/pay.md doc at sherpa's path, yours — covers the entry
102
+ ? .claude/notes.txt unknown yours
103
+ · CLAUDE.md root no sherpa markers — `apply` appends its block (ADR-0016)
104
+ gaps:
105
+ - .claude/agents/pay-expert.md: 175 lines, no knowledge manifest — rotation candidate, facts belong in an owner doc
106
+ - .claude/docs/modules/legacy.md: no unit matches by name or path mentions — moved, renamed or not a module doc
107
+ state: 6 adopted, 0 rebuilt, 0 kept, 0 dropped · harness_rev 592b1a201d0c → .sherpa/state.json · 2 plan entries covered → .sherpa/harness-plan.yaml
108
+ ```
109
+
110
+ The next `sherpa plan` shows `[covered by .claude/agents/pay-expert.md]` on the agent entry and `apply` creates
111
+ nothing there ([golden](tests/goldens/active-plan-covered-console.txt)). The same command rebuilds a lost or torn
112
+ `.sherpa/state.json` from the files — same `harness_rev` as `apply` wrote (ADR-0017).
113
+
114
+ - `sherpa scan` 🟢 **Live** — deterministic codebase model (git churn, hotspots, modules, dependencies, generators)
115
+ - `sherpa plan` 🟢 **Live** — proposals and reasoned no's with evidence as YAML; decisions survive a re-plan or come from the command line (`--accept agent:pay`)
116
+ - `sherpa apply` 🟢 **Live** — dry run first, managed blocks, state file, outcome hook, checker with rollback; targets `claude` and `agents-md` from one neutral core
117
+ - `sherpa status` · `sherpa check` 🟢 **Live** — drift per file and block, structural rules, outcome labels per harness version
118
+ - `sherpa adopt` 🟢 **Live** — take an existing harness into the state without changing a byte; files that already fill a plan entry cover it, and a nested `AGENTS.md` at a unit's own path is its owner doc (no skeleton next to it); a lost state is rebuilt from the files
119
+ - `sherpa doctor` · `sherpa self-update` 🟢 **Live** — every prerequisite with a fix; the next release via the installer that owns this copy; a daily hint that never blocks
120
+
121
+ Documentation: [docs/index.md](docs/index.md) — [getting started](docs/getting-started.md), one reference page per command ([scan](docs/commands/scan.md), [plan](docs/commands/plan.md), [apply](docs/commands/apply.md), [adopt](docs/commands/adopt.md), [status](docs/commands/status.md), [check](docs/commands/check.md), [doctor](docs/commands/doctor.md), [self-update](docs/commands/self-update.md)), [configuration](docs/reference/configuration.md); milestones: [docs/plan.md](docs/plan.md).
122
+
123
+ ## Quick start
124
+
125
+ One line, no clone — the wheel `sherparc` is on [PyPI](https://pypi.org/project/sherparc/) and attached to every [release](https://github.com/sherparc/Sherpa/releases); `sherpa self-update` fetches the next one:
126
+
127
+ ```bash
128
+ uv tool install sherparc # or: pipx install sherparc; from the repository: …install git+https://github.com/sherparc/Sherpa.git
129
+ sherpa doctor # Python, git, origin, trunk, runtime, layout, nested repositories, install, update — with a fix each
130
+ sherpa plan /path/to/repo # scans when needed → .sherpa/harness-plan.yaml
131
+ sherpa apply /path/to/repo # dry run, then asks → .claude/**, .sherpa/state.json
132
+ sherpa adopt /path/to/repo # an existing harness enters the state, not a byte changes
133
+ sherpa status /path/to/repo # drift, checks, outcome labels
134
+ sherpa check /path/to/repo # the structural rules alone (also as a deployed copy, no sherpa needed)
135
+ sherpa apply /path/to/repo --remove # the uninstall: takes back what sherpa wrote and nobody changed
136
+ sherpa scan /path/to/repo --out - # model only, JSON to stdout
137
+ ```
138
+
139
+ For development, the classic way:
140
+
141
+ ```bash
142
+ git clone git@github.com:sherparc/Sherpa.git && cd Sherpa
143
+ python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
144
+ ```
145
+
146
+ Optional `sherpa.toml` in the target repo:
147
+
148
+ ```toml
149
+ [scan]
150
+ trunk = "origin/develop" # otherwise: origin/HEAD, then main/master/dev/develop/trunk
151
+ hotspots = 20
152
+ generated = ["gen/**"] # own generator family, extends the built-in ones
153
+
154
+ [plan]
155
+ agent_top = 0.25 # top quartile by commits/90d …
156
+ agent_min_commits_90d = 20 # … and floors; all values in docs/reference/configuration.md
157
+ ```
158
+
159
+ ## What the scanner measures
160
+
161
+ - **T0 git** — trunk detection, commits/authors in 90- and 30-day windows, LOC per file, hotspots (`commits_90d × loc`, generated files excluded), directory churn.
162
+ - **T1 modules** — from manifests for .NET (`.csproj`), Python (`pyproject.toml`), Node (`package.json`), Go (`go.mod`), Rust (`Cargo.toml`), Java (`pom.xml`, Gradle); in-repo dependencies in both directions, test modules and `tested_by`, module churn, conventions (languages, CI, containers).
163
+ - **Change coupling** — which modules change together (Tornhill's temporal coupling), measured only on commits below a size cap so squash-merge trunks stay honest; one row in every facts block: `changes together with: core (15 of 24 commits, 62 %)`. Sub-directories per module make a single-package repository a plan with units too.
164
+ - **Generator families** — EF/Django/Alembic migrations, protobuf, OpenAPI, GraphQL codegen, ResX, `go generate`, snapshots, bundles, lockfiles: per family output, sources, config, central place and regeneration command — by path only, in 30 ms for 15k files.
165
+ - **T2 language adapters** (M3b) — anchors and patterns per language; T0/T1 work without them.
166
+
167
+ All fields are described in the JSON schema: [codebase-model.schema.json](src/sherpa/schemas/codebase-model.schema.json). Details, decisions and interpretation: [docs/concepts/scan.md](docs/concepts/scan.md).
168
+
169
+ ## What the planner decides
170
+
171
+ Thresholds are **relative with an absolute floor** — top quartile *and* at least 20 commits, 30 files, 2 authors
172
+ for an agent; top 2 by momentum *and* a floor for a librarian. A five-person repo gets an agent, a fifty-module
173
+ repo does not get thirty. Every no names what is missing and when it flips. Modules and directories without a
174
+ module (`infrastructure/`, `pipelines/`) rank on equal terms; test infrastructure is measured against the most
175
+ active business module. Rules, format and configuration: [docs/concepts/harness-plan.md](docs/concepts/harness-plan.md).
176
+
177
+ ### Determinism guarantees
178
+
179
+ - Always against `origin/<trunk>`, never against the checked-out `HEAD` (local branches are invisible).
180
+ - `as_of` = committer date of the trunk rev → same rev, same model, byte-identical (tested).
181
+ - Sorted JSON output, no merge commits in the time windows, no LLM calls in the scanner.
182
+
183
+ ## Why Sherpa
184
+
185
+ Why not just write a few `.md` files for Claude or Copilot?
186
+
187
+ - **No more guessing.** Sherpa builds on hard data — commits, authors, LOC, churn — not on gut feeling. Every proposal carries its evidence, every no its reason.
188
+ - **Infrastructure as code for knowledge.** `plan` → approval → `apply`, like Terraform. You see every file before it exists; Sherpa owns only marked blocks inside the files, the rest is yours and stays yours.
189
+ - **Does not wreck your repo.** Sherpa never overwrites what exists — it creates, appends and merges, and rewrites only its own unchanged bytes. Deterministic against `origin/trunk`, local branches invisible, idempotent with a state file, a checker that rolls back a bad write.
190
+ - **Measures itself.** Every `apply` installs the outcome hook first: each Claude Code execution gets a label (`success`, `failed`, `unknown`) stamped with the harness version. A harness change has a number to answer to.
191
+ - **Grows with you.** Librarians keep owner docs current, evals come from the dependency graph, and the outcome shows which harness parts really help — nothing on the market does that.
192
+
193
+ Where the patterns come from:
194
+
195
+ | Proven on the market | What Sherpa takes from it |
196
+ |---|---|
197
+ | Terraform `plan` / `apply` / `import` / state | proposal before change, approval, idempotency, `adopt` for existing harnesses |
198
+ | CodeScene / Tornhill hotspots | churn × complexity instead of gut feeling; relative thresholds with an absolute floor |
199
+ | Backstage catalog / scaffolder | modules as a catalogue, templates seeded once |
200
+ | `AGENTS.md` / Agent Skills (Codex, Cursor, Gemini CLI, Copilot, …) | proximity loading — the closest file wins — filled with measured facts and kept current instead of hand-written |
201
+ | Ansible `blockinfile` | managed blocks inside co-authored files instead of all-or-nothing ownership |
202
+ | Renovate | librarians as bots with scope and cadence |
203
+ | `brew doctor` | `sherpa doctor` for onboarding |
204
+
205
+ ## Architecture
206
+
207
+ ```mermaid
208
+ flowchart LR
209
+ R[(repo · origin/trunk)] -->|git, manifests| S[sherpa scan]
210
+ S --> M[codebase-model.json]
211
+ M --> P[sherpa plan]
212
+ P --> Y[harness-plan.yaml<br/>proposals + reasoned no's<br/>--accept / --reject]
213
+ Y -->|approval| A[sherpa apply]
214
+ A --> H["{home}/** owner docs · skills · checker<br/>(home = .agents or .claude)"]
215
+ A --> T["adapters per target<br/>claude: .claude/agents · hooks · CLAUDE.md<br/>agents-md: AGENTS.md root + nested<br/>planned, thin on agents-md: hermes · codex · opencode · copilot · cursor · gemini"]
216
+ A --> ST[.sherpa/state.json · harness_rev]
217
+ T -->|outcome hook| O[.sherpa/telemetry/outcomes.ndjson]
218
+ ST --> Q[sherpa status]
219
+ O --> Q
220
+ H --> C[sherpa check<br/>rollback on a new FAIL]
221
+ T --> C
222
+ H -.->|existing| AD[sherpa adopt] -.-> ST
223
+ P -. planned, M6-lite: comments only .-> L[LLM provider<br/>OpenAI-compatible · Anthropic]
224
+ ```
225
+
226
+ - Python 3.12, stdlib-first, one runtime dependency (PyYAML for the plan).
227
+ - Scanner, planner and applier are deterministic today; no LLM call anywhere in the shipped pipeline.
228
+ - Planned (M6-lite): LLMs only in `plan` stage 2, enriching comments, never the entries themselves.
229
+ - Planned (M6-lite): a provider layer without LangChain — local vLLM/Ollama/OpenRouter via the OpenAI API plus Anthropic natively.
230
+
231
+ ## Roadmap
232
+
233
+ | Milestone | Content | Status |
234
+ |---|---|---|
235
+ | M0 | skeleton, ADRs, the plan | ✅ |
236
+ | M1 | scanner T0 for every language: trunk, churn, hotspots, file tree, generated files, JSON schema | ✅ |
237
+ | M1a | scanner T1: modules from manifests (6 ecosystems), in-repo deps, `tested_by`, churn per module | ✅ |
238
+ | M2 | `plan` stage 1: units, rank + floor, generator families → skills, reasoned no's, decision keeping | ✅ |
239
+ | M3a | `apply`: dry run, managed blocks, state, outcome hook, checker with rollback; `status`, `check` | ✅ |
240
+ | M3t | target layer: neutral core under `.agents`/`.claude`, adapters `claude` and `agents-md`, nested proximity files | ✅ |
241
+ | M3c | `adopt`: existing harnesses taken over unchanged, covered entries, rebuildable state | ✅ |
242
+ | M2b | distribution: release wheel per tag, `doctor`, `self-update` (API with a token, `git ls-remote` without), daily hint | ✅ |
243
+ | M3d | retro fruit: stamp without rev, sub-units for single-manifest repos, change coupling with a size cap, `plan --accept/--reject`, capped root index | ✅ |
244
+ | M3e | review fruit: `status` names a stale plan, `status --json` and `doctor --json`, manifest tie-break by language share, coupling without the root catch-all, sub-units for a dominant root module, proximity-file budgets in the checker | ✅ |
245
+ | M3f | write safety: `apply` compares every file with the preview's read before writing, never writes through a symlink, writes each file whole or not at all and rolls back on a write error; `adopt` treats a differing base file as yours, takes a stale plan and rebuilds a torn state without a dead end; a dry run never refuses (two homes → assumes `.agents` and says so) and names a target directory that is a repository of its own | ✅ |
246
+ | M3i | the manager sees what exists and takes back what is sherpa's: refuses on a nested repository (`doctor` says it first), a hand-written `covered:` is kept like a decision, the checker fails only in sherpa's own files; `apply` removes a rejected entry's files when they are still sherpa's and `apply --remove` uninstalls — a clean repository is clean again | ✅ |
247
+ | M3j | owner docs where the team already writes them: a nested `AGENTS.md` at a unit's own path covers its owner-doc entry — `plan` sets it from the file, `adopt` reports it, `apply` writes the facts block into the team's file and no skeleton next to it (first slice, ADR-0049) | ✅ |
248
+ | M2c | public release: the licence flipped to PolyForm Small Business or Noncommercial (ADR-0051) ✅ · the contribution path — DCO checked on every pull request, code of conduct, security policy, templates (ADR-0052) ✅ · the wheel on PyPI as `sherparc` through trusted publishing, `self-update` and `doctor` read the index first (ADR-0053, ADR-0054) ✅ · the demo card at the top of this README, Sherpa on itself ✅ · still to do: a changelog, then the announcement | ⏳ |
249
+ | M3h | `hermes` target: Hermes Agent reads the harness (`AGENTS.md` chain, `.agents/skills`), outcome hook for both runtimes, `doctor` checks for trust and hook wiring | ⏳ |
250
+ | M3k | host adapters `codex`, `opencode`, `copilot`, `cursor`, `gemini` — thin on top of `agents-md` like `hermes`: `doctor` names the host, its native rule file only where `AGENTS.md` cannot carry it, the outcome hook where the host has hooks | ⏳ |
251
+ | M5 | outcome evaluation: `status` shows labels per `harness_rev` with `n` and the share of `unknown`; a comparison between revisions from 30 labelled executions each | ⏳ |
252
+ | M7a | runtime plugins: Sherpa installable inside Claude Code (plugin) and Hermes (bundle) — `/sherpa-plan` with per-entry approval, `/sherpa-apply`, `/sherpa-status`; thin, the CLI does the work | ⏳ |
253
+ | M6-lite | provider layer: thin, framework-free — bring your own key, local models via the OpenAI API, Anthropic natively | ⏳ |
254
+ | M4 | auto-evals from the dependency graph, `status` with a baseline | ⏳ |
255
+ | M6 | `plan` stage 2: LLM enrichment on top of the provider layer | ⏳ |
256
+ | M3b | language adapters `dotnet` + `python` (T2: anchors, patterns) | ⏳ |
257
+ | M7 | librarians, multi-repo | ⏳ |
258
+
259
+ Order from here: M3j's second slice → M3h → M3k → M5 → M7a → M6-lite → M4 → M6 → M3b → M7 (plan §7.3, §9, §9.1, §10, §13).
260
+
261
+ Complete with reasoning: [docs/plan.md](docs/plan.md) · every decision as an ADR: [docs/adr/](docs/adr/README.md)
262
+
263
+ ## Related
264
+
265
+ | Project | What it is | Where Sherpa differs |
266
+ |---|---|---|
267
+ | [metaharness](https://github.com/ruvnet/metaharness) | a factory: scaffolds a new, branded agent-harness package (own `npx` CLI, MCP server, signed releases) from a static read of manifests, for ten hosts | Sherpa writes into the repository you have, from its git history, with a reason for every entry and every no, and keeps it current — `adopt`, `status`, outcome labels per harness version |
268
+ | Claude Code `/init`, auto-memory · Hermes Agent's self-written skills | the runtimes' own way to grow a harness: LLM prose, per person, unreviewed | facts from `git log`, deterministic, reviewed in the PR like code, per team and repository; runtime-neutral (plan §9) |
269
+
270
+ ## License
271
+
272
+ [PolyForm Small Business 1.0.0](LICENSE) or [PolyForm Noncommercial 1.0.0](LICENSE), at your option: free for personal use, for noncommercial organisations and for companies under 100 people and USD 1M revenue; larger companies need a commercial licence. Everything Sherpa generates in your repo is yours, no strings attached. Reasoning in [ADR-0051](docs/adr/0051-public-release-polyform-small-business-or-noncommercial.md).
273
+
274
+ ## Development
275
+
276
+ ```bash
277
+ .venv/bin/pytest -q --cov=sherpa # 439 tests, ~97 % coverage, gate in CI: 90 %
278
+ .venv/bin/ruff check . && .venv/bin/ruff format --check .
279
+ ```
280
+
281
+ CI runs with Python 3.12 and 3.13: Linux on every pull request, Linux and Windows on `main`, macOS weekly; a manual run covers all three. Test repos are built programmatically (no corpus in the repo). The repository carries its own harness — `sherpa status .` must be clean before a commit — and an architect agent under [.claude/agents/](.claude/agents/architect.md). Working rules for humans and agents: [CLAUDE.md](CLAUDE.md).
282
+
283
+ `main` changes only through pull requests with squash merge, every commit signed off (DCO). Once per clone, enable the hooks — the guard that refuses direct pushes to `main` and the one that adds the sign-off:
284
+
285
+ ```bash
286
+ git config core.hooksPath .githooks
287
+ ```
288
+
289
+ Contributions: [CONTRIBUTING.md](CONTRIBUTING.md) · security reports: [SECURITY.md](SECURITY.md) · conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sherparc" # the PyPI name: "sherpa" is taken, the org name is one word (ADR-0054); import package and CLI stay "sherpa"
7
+ version = "0.8.1"
8
+ description = "Generic AI-harness generator: scan the codebase, plan owner docs, agents and skills, create them after approval."
9
+ license = "PolyForm-Small-Business-1.0.0 OR PolyForm-Noncommercial-1.0.0" # ADR-0051: free for individuals, noncommercial organisations and small companies
10
+ license-files = ["LICENSE"]
11
+ requires-python = ">=3.12"
12
+ dependencies = ["pyyaml>=6"] # the only runtime dependency (ADR-0005)
13
+
14
+ [project.scripts]
15
+ sherpa = "sherpa.cli:main"
16
+
17
+ [project.optional-dependencies]
18
+ dev = ["pytest>=8", "pytest-cov>=5", "jsonschema>=4", "ruff>=0.6"] # jsonschema: the reference the stdlib validator is tested against (ADR-0042), never a runtime dependency
19
+
20
+ [tool.setuptools.packages.find]
21
+ where = ["src"]
22
+
23
+ [tool.setuptools.package-data]
24
+ sherpa = ["schemas/*.json", "apply/assets/*.py"]
25
+
26
+ [tool.pytest.ini_options]
27
+ testpaths = ["tests"]
28
+
29
+ [tool.ruff]
30
+ line-length = 120
31
+ target-version = "py312"
32
+
33
+ [tool.ruff.lint]
34
+ select = ["E", "F", "W", "I", "B", "UP"]
35
+
36
+ [tool.ruff.lint.per-file-ignores]
37
+ "tests/*" = ["E501"] # fixture literals (manifest contents) are deliberately long
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "0.8.1"