aptitude-resolver 0.1.0__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 (92) hide show
  1. aptitude_resolver-0.1.0/PKG-INFO +333 -0
  2. aptitude_resolver-0.1.0/README.md +312 -0
  3. aptitude_resolver-0.1.0/pyproject.toml +54 -0
  4. aptitude_resolver-0.1.0/src/aptitude_resolver/__init__.py +1 -0
  5. aptitude_resolver-0.1.0/src/aptitude_resolver/application/__init__.py +1 -0
  6. aptitude_resolver-0.1.0/src/aptitude_resolver/application/composition.py +331 -0
  7. aptitude_resolver-0.1.0/src/aptitude_resolver/application/dto/__init__.py +59 -0
  8. aptitude_resolver-0.1.0/src/aptitude_resolver/application/dto/install_dto.py +88 -0
  9. aptitude_resolver-0.1.0/src/aptitude_resolver/application/dto/resolve_request_dto.py +20 -0
  10. aptitude_resolver-0.1.0/src/aptitude_resolver/application/dto/resolve_result_dto.py +263 -0
  11. aptitude_resolver-0.1.0/src/aptitude_resolver/application/queries/__init__.py +13 -0
  12. aptitude_resolver-0.1.0/src/aptitude_resolver/application/queries/plan_skill_resolution.py +370 -0
  13. aptitude_resolver-0.1.0/src/aptitude_resolver/application/use_cases/__init__.py +13 -0
  14. aptitude_resolver-0.1.0/src/aptitude_resolver/application/use_cases/install_skill.py +139 -0
  15. aptitude_resolver-0.1.0/src/aptitude_resolver/application/use_cases/resolution_mapping.py +259 -0
  16. aptitude_resolver-0.1.0/src/aptitude_resolver/application/use_cases/resolve_skill_query.py +86 -0
  17. aptitude_resolver-0.1.0/src/aptitude_resolver/application/use_cases/sync_from_lock.py +100 -0
  18. aptitude_resolver-0.1.0/src/aptitude_resolver/cache/__init__.py +20 -0
  19. aptitude_resolver-0.1.0/src/aptitude_resolver/cache/keys.py +34 -0
  20. aptitude_resolver-0.1.0/src/aptitude_resolver/cache/store.py +61 -0
  21. aptitude_resolver-0.1.0/src/aptitude_resolver/discovery/__init__.py +13 -0
  22. aptitude_resolver-0.1.0/src/aptitude_resolver/discovery/candidate_discovery.py +155 -0
  23. aptitude_resolver-0.1.0/src/aptitude_resolver/discovery/intent/__init__.py +8 -0
  24. aptitude_resolver-0.1.0/src/aptitude_resolver/discovery/intent/parsing.py +63 -0
  25. aptitude_resolver-0.1.0/src/aptitude_resolver/discovery/query_builder/__init__.py +5 -0
  26. aptitude_resolver-0.1.0/src/aptitude_resolver/discovery/query_builder/build_query.py +17 -0
  27. aptitude_resolver-0.1.0/src/aptitude_resolver/discovery/reranking/__init__.py +5 -0
  28. aptitude_resolver-0.1.0/src/aptitude_resolver/discovery/reranking/candidate_reranker.py +584 -0
  29. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/__init__.py +1 -0
  30. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/errors/__init__.py +41 -0
  31. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/errors/resolver_errors.py +188 -0
  32. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/__init__.py +33 -0
  33. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/dependency_spec.py +16 -0
  34. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/discovered_skill.py +15 -0
  35. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/discovery_candidate.py +26 -0
  36. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/discovery_query.py +16 -0
  37. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/resolution_graph.py +59 -0
  38. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/search_intent.py +18 -0
  39. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/skill_coordinate.py +13 -0
  40. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/skill_identity.py +21 -0
  41. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/skill_metadata.py +31 -0
  42. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/models/version_summary.py +29 -0
  43. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/policy/__init__.py +26 -0
  44. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/policy/models.py +97 -0
  45. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/policy/ranking.py +33 -0
  46. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/policy/selection.py +40 -0
  47. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/tracing/__init__.py +5 -0
  48. aptitude_resolver-0.1.0/src/aptitude_resolver/domain/tracing/models.py +15 -0
  49. aptitude_resolver-0.1.0/src/aptitude_resolver/execution/__init__.py +29 -0
  50. aptitude_resolver-0.1.0/src/aptitude_resolver/execution/debug_artifacts.py +107 -0
  51. aptitude_resolver-0.1.0/src/aptitude_resolver/execution/materialize.py +174 -0
  52. aptitude_resolver-0.1.0/src/aptitude_resolver/execution/plan.py +67 -0
  53. aptitude_resolver-0.1.0/src/aptitude_resolver/governance/__init__.py +8 -0
  54. aptitude_resolver-0.1.0/src/aptitude_resolver/governance/evaluator.py +304 -0
  55. aptitude_resolver-0.1.0/src/aptitude_resolver/interfaces/__init__.py +1 -0
  56. aptitude_resolver-0.1.0/src/aptitude_resolver/interfaces/cli/__init__.py +5 -0
  57. aptitude_resolver-0.1.0/src/aptitude_resolver/interfaces/cli/app.py +586 -0
  58. aptitude_resolver-0.1.0/src/aptitude_resolver/interfaces/cli/main.py +28 -0
  59. aptitude_resolver-0.1.0/src/aptitude_resolver/interfaces/shared/__init__.py +9 -0
  60. aptitude_resolver-0.1.0/src/aptitude_resolver/interfaces/shared/install_workflow.py +233 -0
  61. aptitude_resolver-0.1.0/src/aptitude_resolver/interfaces/tui/__init__.py +5 -0
  62. aptitude_resolver-0.1.0/src/aptitude_resolver/interfaces/tui/app.py +671 -0
  63. aptitude_resolver-0.1.0/src/aptitude_resolver/lockfile/__init__.py +35 -0
  64. aptitude_resolver-0.1.0/src/aptitude_resolver/lockfile/model.py +97 -0
  65. aptitude_resolver-0.1.0/src/aptitude_resolver/lockfile/parser.py +247 -0
  66. aptitude_resolver-0.1.0/src/aptitude_resolver/lockfile/replay.py +91 -0
  67. aptitude_resolver-0.1.0/src/aptitude_resolver/lockfile/serializer.py +247 -0
  68. aptitude_resolver-0.1.0/src/aptitude_resolver/registry/__init__.py +5 -0
  69. aptitude_resolver-0.1.0/src/aptitude_resolver/registry/client.py +344 -0
  70. aptitude_resolver-0.1.0/src/aptitude_resolver/registry/mappers.py +108 -0
  71. aptitude_resolver-0.1.0/src/aptitude_resolver/registry/transport_models.py +125 -0
  72. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/__init__.py +1 -0
  73. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/conflict/__init__.py +7 -0
  74. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/conflict/conflict_rules.py +20 -0
  75. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/graph/__init__.py +7 -0
  76. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/graph/recursive_graph_resolver.py +246 -0
  77. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/normalizer/__init__.py +7 -0
  78. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/normalizer/dependency_normalizer.py +22 -0
  79. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/solver/__init__.py +19 -0
  80. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/solver/candidate_selection.py +92 -0
  81. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/solver/candidate_version_resolution.py +228 -0
  82. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/solver/version_selection.py +41 -0
  83. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/validation/__init__.py +7 -0
  84. aptitude_resolver-0.1.0/src/aptitude_resolver/resolver/validation/graph_validator.py +18 -0
  85. aptitude_resolver-0.1.0/src/aptitude_resolver/shared/__init__.py +1 -0
  86. aptitude_resolver-0.1.0/src/aptitude_resolver/shared/config/__init__.py +27 -0
  87. aptitude_resolver-0.1.0/src/aptitude_resolver/shared/config/aptitude_config.py +133 -0
  88. aptitude_resolver-0.1.0/src/aptitude_resolver/shared/config/settings.py +26 -0
  89. aptitude_resolver-0.1.0/src/aptitude_resolver/shared/logging/__init__.py +5 -0
  90. aptitude_resolver-0.1.0/src/aptitude_resolver/shared/logging/configure.py +27 -0
  91. aptitude_resolver-0.1.0/src/aptitude_resolver/telemetry/__init__.py +9 -0
  92. aptitude_resolver-0.1.0/src/aptitude_resolver/telemetry/metrics.py +61 -0
@@ -0,0 +1,333 @@
1
+ Metadata-Version: 2.3
2
+ Name: aptitude-resolver
3
+ Version: 0.1.0
4
+ Summary: Deterministic package-manager-style resolver for AI skills
5
+ Requires-Dist: diskcache>=5.6
6
+ Requires-Dist: httpx>=0.27
7
+ Requires-Dist: packaging>=24.0
8
+ Requires-Dist: pydantic>=2.0
9
+ Requires-Dist: pydantic-settings>=2.0
10
+ Requires-Dist: structlog>=25.0
11
+ Requires-Dist: tenacity>=9.0
12
+ Requires-Dist: textual>=8.1.1
13
+ Requires-Dist: tomli>=2.0 ; python_full_version < '3.11'
14
+ Requires-Dist: typer>=0.12
15
+ Requires-Dist: mypy>=1.0 ; extra == 'dev'
16
+ Requires-Dist: pytest>=8.0 ; extra == 'dev'
17
+ Requires-Dist: ruff>=0.0.1 ; extra == 'dev'
18
+ Requires-Python: >=3.9
19
+ Provides-Extra: dev
20
+ Description-Content-Type: text/markdown
21
+
22
+ # Aptitude Resolver
23
+
24
+ ![Python](https://img.shields.io/badge/python-3.9%2B-3776AB?style=for-the-badge&logo=python&logoColor=white)
25
+ ![uv](https://img.shields.io/badge/uv-managed-6E56CF?style=for-the-badge&logo=uv&logoColor=white)
26
+ ![Pydantic](https://img.shields.io/badge/pydantic-E92063?style=for-the-badge&logo=pydantic&logoColor=white)
27
+ ![pytest](https://img.shields.io/badge/pytest-0A9EDC?style=for-the-badge&logo=pytest&logoColor=white)
28
+ ![Ruff](https://img.shields.io/badge/ruff-D7FF64?style=for-the-badge&logo=ruff&logoColor=111111)
29
+ [![DeepWiki](https://img.shields.io/badge/Ask-DeepWiki-0A66C2?style=for-the-badge&logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAsVBMVEVHcEwmWMYZy38Akt0gwZoSaFIbYssUmr4gwJkBlN4WbNE4acofwZkBj9k4aMkBk94WgM0bsIM4aMkewJc2ZMM3Z8cbvIwYpHsewJYAftgBkt0fvpgBkt0cv44cv5wzYckAjtsCk90pasUboXsgwJkfwpYfwJg4aMoct44yXswAkd0BkN84Z8cBktwduZIjcO85lM4hwZo5acoBleA6a88iyaABmOQ8b9QhxZ0CnOoizaOW4DOvAAAAMHRSTlMAKCfW%2FAgWA%2F7%2FDfvMc9j7MU%2Frj3XBcRW%2FJMbe7kUxjI%2FlUzzz6tPQkJ%2BjVmW1oeulmmslAAAByUlEQVQ4y32Tia6jIBSGUVFcqliXtlq73rm3d50ERNC%2B%2F4PNQetoptMeE0PgC%2F9%2FFhCaBSH9Hz2J%2BONgPDl2DolSUWY%2FPL8oEQRCfPxHpFc3Ah5wHoiI6I05NXgjAOgQF3Jn1Dlo4XMPDDes09UE2d%2BREvl3lijBg4CrHNmrbcM2u9u5nwsRcAFfFHFY5sZ607Yua3GqpQiKE6G9cZHZThblZ4T2mLnMxde3ATASMUj72o0Pbs1fADDcLHqAjEDugJ3lC%2BztMGYTADcoLaFyH%2B02DP9%2BWS4ahrXE4laALFKcq8vZfscNY8312mxfr27bLJZjnsYhSDIHmUxLu9h9N%2Fep%2B7pazwoZQw%2B1Nwi33epu7c2p8RooeqCdAHMGoOJIq3CUwIMEniRIaHVe3ZVnO2Vgsh1MstEkQUXVUc%2BjXfk3zbemxS6%2BpQmlPtUeALJ8VKj4JHvAelBqFFdSS3h1SPzQKr%2F%2BaRa0%2B0cCIWtJLauG5U%2FfbgyG01uiNqQhyzA8ddKj1OvK28AsZyN3DKE4X6AEWrU1jJx9N7RFpdPxpHU%2FtMOQG9SjfTp3Yz8KgRVKpfx88Dqhpseq606h%2F%2Bzxfh6LJ8eEDKWbxx9XEDwqzP1SVgAAAABJRU5ErkJggg%3D%3D)](https://deepwiki.com/y0ncha/aptitude-client)
30
+ ![Last Commit](https://img.shields.io/github/last-commit/aptitude-stack/resolver?style=for-the-badge)
31
+
32
+ Aptitude Resolver is a deterministic, package-manager-style resolver for AI skills.
33
+
34
+ The system is intentionally split in two:
35
+
36
+ - Aptitude Server owns registry data, metadata, immutable artifacts, and discovery indexes
37
+ - Aptitude Resolver owns intent interpretation, candidate selection, dependency resolution, governance, lock generation, and execution planning
38
+
39
+ ## Current CLI
40
+
41
+ Primary commands:
42
+
43
+ - `aptitude install "<query>"`
44
+ - `aptitude sync --lock aptitude.lock.json`
45
+
46
+ Internal preview command:
47
+
48
+ - `aptitude resolve "<query>"`
49
+
50
+ `resolve` still exists for preview, debugging, and CI, but it is hidden from normal CLI help. The normal user-facing flow is `install`.
51
+
52
+ ## How To Install
53
+
54
+ Install the resolver and its development dependencies with `uv`:
55
+
56
+ ```bash
57
+ uv sync --extra dev
58
+ ```
59
+
60
+ This creates the local environment from `pyproject.toml` and makes the `aptitude` entrypoint available through `uv run` or an activated environment.
61
+
62
+ ## Packaging And Publishing
63
+
64
+ This project builds and publishes as a normal Python package. `uv` is the build tool, and the release registry is PyPI. There is no separate special "uv registry" format.
65
+
66
+ The packaging metadata lives in `pyproject.toml`:
67
+
68
+ - `[project]` defines the package name, version, dependencies, and console entry point
69
+ - `[project.scripts]` maps the installed `aptitude` command to `aptitude_resolver.interfaces.cli.main:main`
70
+ - `[build-system]` tells `uv` to build the package with `uv_build`
71
+
72
+ Build the package artifacts locally:
73
+
74
+ ```bash
75
+ make package
76
+ ```
77
+
78
+ `make package` runs `uv build --no-sources` and creates:
79
+
80
+ ```text
81
+ dist/*.whl
82
+ dist/*.tar.gz
83
+ ```
84
+
85
+ The wheel is the main installable artifact. It contains the `aptitude_resolver` package, its dependency metadata, and the `aptitude` console script.
86
+
87
+ Publish to PyPI through GitHub Actions trusted publishing:
88
+
89
+ ```bash
90
+ git tag v0.1.0
91
+ git push origin v0.1.0
92
+ ```
93
+
94
+ The release workflow lives at `.github/workflows/publish.yml` and:
95
+
96
+ - triggers on tags matching `v*`
97
+ - builds the wheel and sdist with `uv build --no-sources`
98
+ - publishes with `pypa/gh-action-pypi-publish`
99
+ - authenticates to PyPI with GitHub OIDC trusted publishing
100
+ - does not use PyPI API tokens or repository secrets
101
+
102
+ The publish job uses the GitHub Environment `pypi`. That is not required by PyPI itself, but it is recommended because it gives releases a dedicated protection boundary in GitHub.
103
+
104
+ Install and run after publishing:
105
+
106
+ ```bash
107
+ uv tool install aptitude-resolver
108
+ aptitude --help
109
+ ```
110
+
111
+ For one-off execution without a persistent install:
112
+
113
+ ```bash
114
+ uvx aptitude-resolver --help
115
+ ```
116
+
117
+ Use this mental model:
118
+
119
+ - `make package` builds the distributable artifacts
120
+ - pushing a `v*` tag triggers the trusted publishing workflow
121
+ - `uv tool install aptitude-resolver` installs the published CLI
122
+ - `aptitude ...` is the command end users run after installation
123
+
124
+ ## How To Use
125
+
126
+ For repo-local development, typical usage starts with one of these commands:
127
+
128
+ ```bash
129
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main --help
130
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main install "Postman Primary Skill"
131
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main sync --lock aptitude_resolver.lock.json
132
+ ```
133
+
134
+ Use `install` for fresh planning from a query and `sync --lock` for replaying an existing lockfile. The help text and examples still use the logical `aptitude` command name, but the verified repo-local entrypoint is the module invocation above.
135
+
136
+ For published usage, prefer the installed CLI:
137
+
138
+ ```bash
139
+ aptitude --help
140
+ aptitude install "Postman Primary Skill"
141
+ aptitude sync --lock aptitude.lock.json
142
+ ```
143
+
144
+ ## What Works Today
145
+
146
+ - discovery-backed query resolution from human-readable input
147
+ - resolver-owned candidate version selection
148
+ - deterministic recursive dependency graph resolution
149
+ - candidate-policy filtering and graph governance before lock generation
150
+ - workspace policy loading from `aptitude.toml`
151
+ - hard policy CLI overrides for fresh planning
152
+ - rich lockfile generation, serialization, parsing, and replay
153
+ - lock-driven execution plan generation
154
+ - local materialization from either a fresh plan or an existing lockfile
155
+ - `sync --lock` as the lock-replay equivalent of `uv sync`
156
+ - registry caching and bounded transient retry
157
+ - additive telemetry for planning and materialization stages
158
+ - deterministic lockfiles for identical logical inputs
159
+ - trace output for discovery, selection, resolver, lock, and execution steps
160
+
161
+ ## What Is Still Incomplete
162
+
163
+ - organization-managed policy loading is not implemented yet
164
+ - broader organization-specific rules are not implemented yet
165
+ - winner-vs-runner-up explanation still derives from parallel explanation logic instead of directly from reranker output
166
+ - `plugins/` extensibility is not implemented yet
167
+ - MCP and SDK interfaces are not implemented yet
168
+
169
+ ## Selection, Governance, And Integrity Direction
170
+
171
+ The canonical architecture now defines these required semantics:
172
+
173
+ - server provides immutable metadata such as lifecycle, trust, token, size, and checksum facts
174
+ - resolver owns policy and candidate selection
175
+ - governance is split into:
176
+ - candidate-policy filtering before final ranking and final root selection
177
+ - full graph governance after resolution and before lock generation
178
+ - ranking compares only policy-compliant candidates
179
+ - phase 1 checksum verification uses server-published `sha256` checksum metadata and fails fast on mismatch
180
+
181
+ Current code now implements Governance Phase 1, profile-aware ranking, and explainability snapshots. The canonical source of truth for remaining evolution lives under [docs/README.md](docs/README.md).
182
+
183
+ ## Current User Flows
184
+
185
+ Fresh planning and install:
186
+
187
+ ```text
188
+ install query
189
+ -> discovery
190
+ -> resolver
191
+ -> governance
192
+ -> lockfile
193
+ -> execution plan
194
+ -> materialization
195
+ ```
196
+
197
+ Lock replay:
198
+
199
+ ```text
200
+ sync --lock aptitude.lock.json
201
+ -> lockfile parse
202
+ -> lock replay
203
+ -> execution plan
204
+ -> materialization
205
+ ```
206
+
207
+ ## Example Commands
208
+
209
+ Install from a query:
210
+
211
+ ```bash
212
+ aptitude_resolver install "Postman Primary Skill"
213
+ ```
214
+
215
+ Install as JSON for automation:
216
+
217
+ ```bash
218
+ aptitude_resolver install "Postman Primary Skill" --json
219
+ ```
220
+
221
+ Sync from an existing lockfile:
222
+
223
+ ```bash
224
+ aptitude_resolver sync --lock aptitude_resolver.lock.json
225
+ ```
226
+
227
+ Preview the resolved graph, lock, and execution plan without materializing:
228
+
229
+ ```bash
230
+ uv run python -m aptitude_resolver.interfaces.cli.main resolve "Postman Primary Skill"
231
+ ```
232
+
233
+ ## Current Package Map
234
+
235
+ ```text
236
+ src/aptitude_resolver/
237
+ application/
238
+ dto/
239
+ queries/
240
+ use_cases/
241
+ cache/
242
+ discovery/
243
+ intent/
244
+ query_builder/
245
+ reranking/
246
+ domain/
247
+ errors/
248
+ models/
249
+ policy/
250
+ tracing/
251
+ execution/
252
+ governance/
253
+ interfaces/
254
+ cli/
255
+ lockfile/
256
+ registry/
257
+ resolver/
258
+ conflict/
259
+ graph/
260
+ normalizer/
261
+ replay/
262
+ solver/
263
+ validation/
264
+ shared/
265
+ config/
266
+ logging/
267
+ telemetry/
268
+ ```
269
+
270
+ ## Current Registry Contract Used By The Resolver
271
+
272
+ The resolver currently talks to the live registry through `registry/` using these runtime paths:
273
+
274
+ - `POST /discovery`
275
+ - `GET /skills/{slug}`
276
+ - `GET /skills/{slug}/{version}`
277
+ - `GET /resolution/{slug}/{version}`
278
+ - `GET /skills/{slug}/{version}/content`
279
+
280
+ The resolver treats the server as a source of immutable facts and candidate generation only. Final ranking, version choice, solving, policy enforcement, lock generation, and execution planning remain resolver-owned.
281
+
282
+ ## Development
283
+
284
+ Requirements:
285
+
286
+ - Python `>=3.9`
287
+
288
+ Run the CLI:
289
+
290
+ ```bash
291
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main --help
292
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main install "Postman Primary Skill"
293
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main sync --lock aptitude_resolver.lock.json
294
+ ```
295
+
296
+ Or via Python:
297
+
298
+ ```bash
299
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main --help
300
+ ```
301
+
302
+ Developer workflow:
303
+
304
+ ```bash
305
+ make help
306
+ make format
307
+ make format-check
308
+ make lint
309
+ make typecheck
310
+ make test
311
+ make check
312
+ ```
313
+
314
+ ## Source Of Truth Docs
315
+
316
+ Start with the docs index:
317
+
318
+ - [docs/README.md](docs/README.md)
319
+
320
+ The canonical architecture pair for future implementation work is:
321
+
322
+ - [docs/architecture/system-overview.md](docs/architecture/system-overview.md)
323
+ - [docs/architecture/decision-rules.md](docs/architecture/decision-rules.md)
324
+
325
+ Before any non-trivial implementation or refactor, read both.
326
+
327
+ Supporting docs:
328
+
329
+ - [docs/contributors/README.md](docs/contributors/README.md)
330
+ - [docs/reference/recommended-libraries.md](docs/reference/recommended-libraries.md)
331
+ - [docs/roadmap/README.md](docs/roadmap/README.md)
332
+
333
+ The `docs/reference/openapi/` directory is kept as raw server reference material, not as the sole source of truth for runtime behavior.
@@ -0,0 +1,312 @@
1
+ # Aptitude Resolver
2
+
3
+ ![Python](https://img.shields.io/badge/python-3.9%2B-3776AB?style=for-the-badge&logo=python&logoColor=white)
4
+ ![uv](https://img.shields.io/badge/uv-managed-6E56CF?style=for-the-badge&logo=uv&logoColor=white)
5
+ ![Pydantic](https://img.shields.io/badge/pydantic-E92063?style=for-the-badge&logo=pydantic&logoColor=white)
6
+ ![pytest](https://img.shields.io/badge/pytest-0A9EDC?style=for-the-badge&logo=pytest&logoColor=white)
7
+ ![Ruff](https://img.shields.io/badge/ruff-D7FF64?style=for-the-badge&logo=ruff&logoColor=111111)
8
+ [![DeepWiki](https://img.shields.io/badge/Ask-DeepWiki-0A66C2?style=for-the-badge&logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAsVBMVEVHcEwmWMYZy38Akt0gwZoSaFIbYssUmr4gwJkBlN4WbNE4acofwZkBj9k4aMkBk94WgM0bsIM4aMkewJc2ZMM3Z8cbvIwYpHsewJYAftgBkt0fvpgBkt0cv44cv5wzYckAjtsCk90pasUboXsgwJkfwpYfwJg4aMoct44yXswAkd0BkN84Z8cBktwduZIjcO85lM4hwZo5acoBleA6a88iyaABmOQ8b9QhxZ0CnOoizaOW4DOvAAAAMHRSTlMAKCfW%2FAgWA%2F7%2FDfvMc9j7MU%2Frj3XBcRW%2FJMbe7kUxjI%2FlUzzz6tPQkJ%2BjVmW1oeulmmslAAAByUlEQVQ4y32Tia6jIBSGUVFcqliXtlq73rm3d50ERNC%2B%2F4PNQetoptMeE0PgC%2F9%2FFhCaBSH9Hz2J%2BONgPDl2DolSUWY%2FPL8oEQRCfPxHpFc3Ah5wHoiI6I05NXgjAOgQF3Jn1Dlo4XMPDDes09UE2d%2BREvl3lijBg4CrHNmrbcM2u9u5nwsRcAFfFHFY5sZ607Yua3GqpQiKE6G9cZHZThblZ4T2mLnMxde3ATASMUj72o0Pbs1fADDcLHqAjEDugJ3lC%2BztMGYTADcoLaFyH%2B02DP9%2BWS4ahrXE4laALFKcq8vZfscNY8312mxfr27bLJZjnsYhSDIHmUxLu9h9N%2Fep%2B7pazwoZQw%2B1Nwi33epu7c2p8RooeqCdAHMGoOJIq3CUwIMEniRIaHVe3ZVnO2Vgsh1MstEkQUXVUc%2BjXfk3zbemxS6%2BpQmlPtUeALJ8VKj4JHvAelBqFFdSS3h1SPzQKr%2F%2BaRa0%2B0cCIWtJLauG5U%2FfbgyG01uiNqQhyzA8ddKj1OvK28AsZyN3DKE4X6AEWrU1jJx9N7RFpdPxpHU%2FtMOQG9SjfTp3Yz8KgRVKpfx88Dqhpseq606h%2F%2Bzxfh6LJ8eEDKWbxx9XEDwqzP1SVgAAAABJRU5ErkJggg%3D%3D)](https://deepwiki.com/y0ncha/aptitude-client)
9
+ ![Last Commit](https://img.shields.io/github/last-commit/aptitude-stack/resolver?style=for-the-badge)
10
+
11
+ Aptitude Resolver is a deterministic, package-manager-style resolver for AI skills.
12
+
13
+ The system is intentionally split in two:
14
+
15
+ - Aptitude Server owns registry data, metadata, immutable artifacts, and discovery indexes
16
+ - Aptitude Resolver owns intent interpretation, candidate selection, dependency resolution, governance, lock generation, and execution planning
17
+
18
+ ## Current CLI
19
+
20
+ Primary commands:
21
+
22
+ - `aptitude install "<query>"`
23
+ - `aptitude sync --lock aptitude.lock.json`
24
+
25
+ Internal preview command:
26
+
27
+ - `aptitude resolve "<query>"`
28
+
29
+ `resolve` still exists for preview, debugging, and CI, but it is hidden from normal CLI help. The normal user-facing flow is `install`.
30
+
31
+ ## How To Install
32
+
33
+ Install the resolver and its development dependencies with `uv`:
34
+
35
+ ```bash
36
+ uv sync --extra dev
37
+ ```
38
+
39
+ This creates the local environment from `pyproject.toml` and makes the `aptitude` entrypoint available through `uv run` or an activated environment.
40
+
41
+ ## Packaging And Publishing
42
+
43
+ This project builds and publishes as a normal Python package. `uv` is the build tool, and the release registry is PyPI. There is no separate special "uv registry" format.
44
+
45
+ The packaging metadata lives in `pyproject.toml`:
46
+
47
+ - `[project]` defines the package name, version, dependencies, and console entry point
48
+ - `[project.scripts]` maps the installed `aptitude` command to `aptitude_resolver.interfaces.cli.main:main`
49
+ - `[build-system]` tells `uv` to build the package with `uv_build`
50
+
51
+ Build the package artifacts locally:
52
+
53
+ ```bash
54
+ make package
55
+ ```
56
+
57
+ `make package` runs `uv build --no-sources` and creates:
58
+
59
+ ```text
60
+ dist/*.whl
61
+ dist/*.tar.gz
62
+ ```
63
+
64
+ The wheel is the main installable artifact. It contains the `aptitude_resolver` package, its dependency metadata, and the `aptitude` console script.
65
+
66
+ Publish to PyPI through GitHub Actions trusted publishing:
67
+
68
+ ```bash
69
+ git tag v0.1.0
70
+ git push origin v0.1.0
71
+ ```
72
+
73
+ The release workflow lives at `.github/workflows/publish.yml` and:
74
+
75
+ - triggers on tags matching `v*`
76
+ - builds the wheel and sdist with `uv build --no-sources`
77
+ - publishes with `pypa/gh-action-pypi-publish`
78
+ - authenticates to PyPI with GitHub OIDC trusted publishing
79
+ - does not use PyPI API tokens or repository secrets
80
+
81
+ The publish job uses the GitHub Environment `pypi`. That is not required by PyPI itself, but it is recommended because it gives releases a dedicated protection boundary in GitHub.
82
+
83
+ Install and run after publishing:
84
+
85
+ ```bash
86
+ uv tool install aptitude-resolver
87
+ aptitude --help
88
+ ```
89
+
90
+ For one-off execution without a persistent install:
91
+
92
+ ```bash
93
+ uvx aptitude-resolver --help
94
+ ```
95
+
96
+ Use this mental model:
97
+
98
+ - `make package` builds the distributable artifacts
99
+ - pushing a `v*` tag triggers the trusted publishing workflow
100
+ - `uv tool install aptitude-resolver` installs the published CLI
101
+ - `aptitude ...` is the command end users run after installation
102
+
103
+ ## How To Use
104
+
105
+ For repo-local development, typical usage starts with one of these commands:
106
+
107
+ ```bash
108
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main --help
109
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main install "Postman Primary Skill"
110
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main sync --lock aptitude_resolver.lock.json
111
+ ```
112
+
113
+ Use `install` for fresh planning from a query and `sync --lock` for replaying an existing lockfile. The help text and examples still use the logical `aptitude` command name, but the verified repo-local entrypoint is the module invocation above.
114
+
115
+ For published usage, prefer the installed CLI:
116
+
117
+ ```bash
118
+ aptitude --help
119
+ aptitude install "Postman Primary Skill"
120
+ aptitude sync --lock aptitude.lock.json
121
+ ```
122
+
123
+ ## What Works Today
124
+
125
+ - discovery-backed query resolution from human-readable input
126
+ - resolver-owned candidate version selection
127
+ - deterministic recursive dependency graph resolution
128
+ - candidate-policy filtering and graph governance before lock generation
129
+ - workspace policy loading from `aptitude.toml`
130
+ - hard policy CLI overrides for fresh planning
131
+ - rich lockfile generation, serialization, parsing, and replay
132
+ - lock-driven execution plan generation
133
+ - local materialization from either a fresh plan or an existing lockfile
134
+ - `sync --lock` as the lock-replay equivalent of `uv sync`
135
+ - registry caching and bounded transient retry
136
+ - additive telemetry for planning and materialization stages
137
+ - deterministic lockfiles for identical logical inputs
138
+ - trace output for discovery, selection, resolver, lock, and execution steps
139
+
140
+ ## What Is Still Incomplete
141
+
142
+ - organization-managed policy loading is not implemented yet
143
+ - broader organization-specific rules are not implemented yet
144
+ - winner-vs-runner-up explanation still derives from parallel explanation logic instead of directly from reranker output
145
+ - `plugins/` extensibility is not implemented yet
146
+ - MCP and SDK interfaces are not implemented yet
147
+
148
+ ## Selection, Governance, And Integrity Direction
149
+
150
+ The canonical architecture now defines these required semantics:
151
+
152
+ - server provides immutable metadata such as lifecycle, trust, token, size, and checksum facts
153
+ - resolver owns policy and candidate selection
154
+ - governance is split into:
155
+ - candidate-policy filtering before final ranking and final root selection
156
+ - full graph governance after resolution and before lock generation
157
+ - ranking compares only policy-compliant candidates
158
+ - phase 1 checksum verification uses server-published `sha256` checksum metadata and fails fast on mismatch
159
+
160
+ Current code now implements Governance Phase 1, profile-aware ranking, and explainability snapshots. The canonical source of truth for remaining evolution lives under [docs/README.md](docs/README.md).
161
+
162
+ ## Current User Flows
163
+
164
+ Fresh planning and install:
165
+
166
+ ```text
167
+ install query
168
+ -> discovery
169
+ -> resolver
170
+ -> governance
171
+ -> lockfile
172
+ -> execution plan
173
+ -> materialization
174
+ ```
175
+
176
+ Lock replay:
177
+
178
+ ```text
179
+ sync --lock aptitude.lock.json
180
+ -> lockfile parse
181
+ -> lock replay
182
+ -> execution plan
183
+ -> materialization
184
+ ```
185
+
186
+ ## Example Commands
187
+
188
+ Install from a query:
189
+
190
+ ```bash
191
+ aptitude_resolver install "Postman Primary Skill"
192
+ ```
193
+
194
+ Install as JSON for automation:
195
+
196
+ ```bash
197
+ aptitude_resolver install "Postman Primary Skill" --json
198
+ ```
199
+
200
+ Sync from an existing lockfile:
201
+
202
+ ```bash
203
+ aptitude_resolver sync --lock aptitude_resolver.lock.json
204
+ ```
205
+
206
+ Preview the resolved graph, lock, and execution plan without materializing:
207
+
208
+ ```bash
209
+ uv run python -m aptitude_resolver.interfaces.cli.main resolve "Postman Primary Skill"
210
+ ```
211
+
212
+ ## Current Package Map
213
+
214
+ ```text
215
+ src/aptitude_resolver/
216
+ application/
217
+ dto/
218
+ queries/
219
+ use_cases/
220
+ cache/
221
+ discovery/
222
+ intent/
223
+ query_builder/
224
+ reranking/
225
+ domain/
226
+ errors/
227
+ models/
228
+ policy/
229
+ tracing/
230
+ execution/
231
+ governance/
232
+ interfaces/
233
+ cli/
234
+ lockfile/
235
+ registry/
236
+ resolver/
237
+ conflict/
238
+ graph/
239
+ normalizer/
240
+ replay/
241
+ solver/
242
+ validation/
243
+ shared/
244
+ config/
245
+ logging/
246
+ telemetry/
247
+ ```
248
+
249
+ ## Current Registry Contract Used By The Resolver
250
+
251
+ The resolver currently talks to the live registry through `registry/` using these runtime paths:
252
+
253
+ - `POST /discovery`
254
+ - `GET /skills/{slug}`
255
+ - `GET /skills/{slug}/{version}`
256
+ - `GET /resolution/{slug}/{version}`
257
+ - `GET /skills/{slug}/{version}/content`
258
+
259
+ The resolver treats the server as a source of immutable facts and candidate generation only. Final ranking, version choice, solving, policy enforcement, lock generation, and execution planning remain resolver-owned.
260
+
261
+ ## Development
262
+
263
+ Requirements:
264
+
265
+ - Python `>=3.9`
266
+
267
+ Run the CLI:
268
+
269
+ ```bash
270
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main --help
271
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main install "Postman Primary Skill"
272
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main sync --lock aptitude_resolver.lock.json
273
+ ```
274
+
275
+ Or via Python:
276
+
277
+ ```bash
278
+ PYTHONPATH=src .venv/bin/python -m aptitude_resolver.interfaces.cli.main --help
279
+ ```
280
+
281
+ Developer workflow:
282
+
283
+ ```bash
284
+ make help
285
+ make format
286
+ make format-check
287
+ make lint
288
+ make typecheck
289
+ make test
290
+ make check
291
+ ```
292
+
293
+ ## Source Of Truth Docs
294
+
295
+ Start with the docs index:
296
+
297
+ - [docs/README.md](docs/README.md)
298
+
299
+ The canonical architecture pair for future implementation work is:
300
+
301
+ - [docs/architecture/system-overview.md](docs/architecture/system-overview.md)
302
+ - [docs/architecture/decision-rules.md](docs/architecture/decision-rules.md)
303
+
304
+ Before any non-trivial implementation or refactor, read both.
305
+
306
+ Supporting docs:
307
+
308
+ - [docs/contributors/README.md](docs/contributors/README.md)
309
+ - [docs/reference/recommended-libraries.md](docs/reference/recommended-libraries.md)
310
+ - [docs/roadmap/README.md](docs/roadmap/README.md)
311
+
312
+ The `docs/reference/openapi/` directory is kept as raw server reference material, not as the sole source of truth for runtime behavior.
@@ -0,0 +1,54 @@
1
+ [project]
2
+ name = "aptitude-resolver"
3
+ version = "0.1.0"
4
+ description = "Deterministic package-manager-style resolver for AI skills"
5
+ readme = "README.md"
6
+ requires-python = ">=3.9"
7
+ dependencies = [
8
+ "diskcache>=5.6",
9
+ "httpx>=0.27",
10
+ "packaging>=24.0",
11
+ "pydantic>=2.0",
12
+ "pydantic-settings>=2.0",
13
+ "structlog>=25.0",
14
+ "tenacity>=9.0",
15
+ "textual>=8.1.1",
16
+ "tomli>=2.0; python_version < '3.11'",
17
+ "typer>=0.12",
18
+ ]
19
+
20
+ [project.optional-dependencies]
21
+ dev = [
22
+ "mypy>=1.0",
23
+ "pytest>=8.0",
24
+ "ruff>=0.0.1",
25
+ ]
26
+
27
+ [project.scripts]
28
+ aptitude = "aptitude_resolver.interfaces.cli.main:main"
29
+
30
+ [build-system]
31
+ requires = ["uv_build>=0.10.8,<0.11.0"]
32
+ build-backend = "uv_build"
33
+
34
+ [tool.pytest.ini_options]
35
+ testpaths = ["tests"]
36
+ addopts = "-ra"
37
+ markers = [
38
+ "integration: tests that hit the live Aptitude server",
39
+ ]
40
+
41
+ [tool.mypy]
42
+ python_version = "3.9"
43
+ files = ["src", "tests"]
44
+ show_error_codes = true
45
+ pretty = true
46
+
47
+ [[tool.mypy.overrides]]
48
+ module = ["diskcache", "tomli"]
49
+ ignore_missing_imports = true
50
+
51
+ [[tool.mypy.overrides]]
52
+ module = ["pytest", "_pytest", "_pytest.*"]
53
+ ignore_missing_imports = true
54
+ follow_imports = "skip"
@@ -0,0 +1 @@
1
+ """Aptitude Resolver package."""
@@ -0,0 +1 @@
1
+ """Application layer package."""