shelf-spec 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 (59) hide show
  1. shelf_spec-0.1.0/.gitignore +21 -0
  2. shelf_spec-0.1.0/CHANGELOG.md +29 -0
  3. shelf_spec-0.1.0/LICENSE +21 -0
  4. shelf_spec-0.1.0/PKG-INFO +126 -0
  5. shelf_spec-0.1.0/README.md +95 -0
  6. shelf_spec-0.1.0/adr/README.md +12 -0
  7. shelf_spec-0.1.0/docs/adoption/README.md +41 -0
  8. shelf_spec-0.1.0/pyproject.toml +93 -0
  9. shelf_spec-0.1.0/spec/SPEC.md +469 -0
  10. shelf_spec-0.1.0/spec/examples/multi-reserved/agents.yml +15 -0
  11. shelf_spec-0.1.0/spec/examples/multi-reserved/shelf.yml +20 -0
  12. shelf_spec-0.1.0/spec/examples/single-docshelf/shelf.yml +15 -0
  13. shelf_spec-0.1.0/spec/examples/single-memshelf/shelf.yml +19 -0
  14. shelf_spec-0.1.0/spec/shelf.schema.json +123 -0
  15. shelf_spec-0.1.0/src/shelf_spec/__init__.py +9 -0
  16. shelf_spec-0.1.0/src/shelf_spec/__main__.py +7 -0
  17. shelf_spec-0.1.0/src/shelf_spec/cli.py +169 -0
  18. shelf_spec-0.1.0/src/shelf_spec/config.py +21 -0
  19. shelf_spec-0.1.0/src/shelf_spec/engine/__init__.py +21 -0
  20. shelf_spec-0.1.0/src/shelf_spec/engine/fsutil.py +41 -0
  21. shelf_spec-0.1.0/src/shelf_spec/engine/info.py +83 -0
  22. shelf_spec-0.1.0/src/shelf_spec/engine/initializer.py +181 -0
  23. shelf_spec-0.1.0/src/shelf_spec/engine/manifest.py +193 -0
  24. shelf_spec-0.1.0/src/shelf_spec/engine/validator.py +695 -0
  25. shelf_spec-0.1.0/src/shelf_spec/server.py +228 -0
  26. shelf_spec-0.1.0/tests/__init__.py +0 -0
  27. shelf_spec-0.1.0/tests/conftest.py +40 -0
  28. shelf_spec-0.1.0/tests/fixtures/docshelf_like/.docshelf.json +8 -0
  29. shelf_spec-0.1.0/tests/fixtures/docshelf_like/INDEX.md +16 -0
  30. shelf_spec-0.1.0/tests/fixtures/docshelf_like/docs/books/.meta.json +6 -0
  31. shelf_spec-0.1.0/tests/fixtures/docshelf_like/docs/books/sample-book/001-intro.md +3 -0
  32. shelf_spec-0.1.0/tests/fixtures/docshelf_like/docs/books/sample-book/002-chapter-one.md +3 -0
  33. shelf_spec-0.1.0/tests/fixtures/docshelf_like/docs/books/sample-book.md +9 -0
  34. shelf_spec-0.1.0/tests/fixtures/docshelf_like/shelf.yml +10 -0
  35. shelf_spec-0.1.0/tests/fixtures/legacy_like/DOCS/compressed/WIDGET_3000_HS.pdf.txt +2 -0
  36. shelf_spec-0.1.0/tests/fixtures/legacy_like/DOCS/markdown/BIGDOC/01-chapter-one/0001-first-section.md +4 -0
  37. shelf_spec-0.1.0/tests/fixtures/legacy_like/DOCS/markdown/BIGDOC/01-chapter-one/0002-second-section.md +3 -0
  38. shelf_spec-0.1.0/tests/fixtures/legacy_like/DOCS/markdown/BIGDOC/01-chapter-one/SUBINDEX.md +4 -0
  39. shelf_spec-0.1.0/tests/fixtures/legacy_like/DOCS/markdown/WIDGET_3000_HS.md +4 -0
  40. shelf_spec-0.1.0/tests/fixtures/legacy_like/INDEX.md +19 -0
  41. shelf_spec-0.1.0/tests/fixtures/manifests/legacy_like.shelf.yml +12 -0
  42. shelf_spec-0.1.0/tests/fixtures/memshelf_like/.docshelf.json +12 -0
  43. shelf_spec-0.1.0/tests/fixtures/memshelf_like/INDEX.md +19 -0
  44. shelf_spec-0.1.0/tests/fixtures/memshelf_like/POLICY.md +5 -0
  45. shelf_spec-0.1.0/tests/fixtures/memshelf_like/docs/research/.meta.json +6 -0
  46. shelf_spec-0.1.0/tests/fixtures/memshelf_like/docs/research/2026-01-11-fixture-research.md +21 -0
  47. shelf_spec-0.1.0/tests/fixtures/memshelf_like/docs/sessions/.meta.json +6 -0
  48. shelf_spec-0.1.0/tests/fixtures/memshelf_like/docs/sessions/2026-01-12-fixture-session.md +24 -0
  49. shelf_spec-0.1.0/tests/fixtures/memshelf_like/docs/topics/.meta.json +6 -0
  50. shelf_spec-0.1.0/tests/fixtures/memshelf_like/docs/topics/2026-01-10-fixture-topic.md +22 -0
  51. shelf_spec-0.1.0/tests/fixtures/memshelf_like/ledger.tsv +4 -0
  52. shelf_spec-0.1.0/tests/fixtures/memshelf_like/shelf.yml +16 -0
  53. shelf_spec-0.1.0/tests/test_cli.py +67 -0
  54. shelf_spec-0.1.0/tests/test_info.py +49 -0
  55. shelf_spec-0.1.0/tests/test_init.py +118 -0
  56. shelf_spec-0.1.0/tests/test_manifest.py +102 -0
  57. shelf_spec-0.1.0/tests/test_server.py +71 -0
  58. shelf_spec-0.1.0/tests/test_spec_examples.py +33 -0
  59. shelf_spec-0.1.0/tests/test_validator.py +391 -0
@@ -0,0 +1,21 @@
1
+ # Python
2
+ __pycache__/
3
+ *.pyc
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+
11
+ # Tooling caches
12
+ .pytest_cache/
13
+ .ruff_cache/
14
+ .coverage
15
+ htmlcov/
16
+
17
+ # OS / editor junk
18
+ .DS_Store
19
+ Thumbs.db
20
+ *.swp
21
+ * 2.*
@@ -0,0 +1,29 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (M0)
4
+
5
+ - Pinned the MCP SDK by major (`mcp>=1.2.0,<2`): mcp 2.0.0 removed
6
+ `mcp.server.fastmcp`, so fresh installs failed to import the server.
7
+ - **Project renamed `openshelf` → `shelf-spec`** (2026-07-26, ADR 0007;
8
+ closes the naming gate #3): package, console script, module
9
+ `shelf_spec`, env `SHELF_SPEC_ROOT` (was `OPENSHELF_ROOT`), schema `$id`,
10
+ repo URLs. Nothing had been published under the old name.
11
+ - shelf-spec v0: `spec/SPEC.md` + `spec/shelf.schema.json` + examples.
12
+ - Engine: manifest loader (schema validation, config-error gate),
13
+ spec validator with severities, idempotent scaffolder, info summary.
14
+ - Thin MCP server (`shelf_init` / `shelf_validate` / `shelf_info`) and
15
+ CLI (`shelf-spec init|validate|info|serve`) over the same engine.
16
+ - `shelf-spec validate --ci` with exit codes 0/1/2 for shelf-repo CI.
17
+ - MCP tools take flat keyword arguments (`{"shelf_path": ...}` in
18
+ `tools/call`) instead of a single nested `params` model.
19
+ - `docs/adoption/`: ready-to-apply `shelf.yml` candidates for the three
20
+ owner shelves (validated green via `--manifest`; committing them into
21
+ the shelf repos is an owner action).
22
+ - Validator: a non-UTF-8 or unreadable `.meta.json` / `ledger.tsv` /
23
+ `.docshelf.json` now degrades to a normal finding instead of aborting
24
+ the CLI with a traceback (#6).
25
+ - Validator: `extra_dirs` entries now suppress `category-undeclared` /
26
+ `orphaned-split-dir` for the declared sidecar directories, and a declared
27
+ directory missing on disk raises the `extra-dir-missing` info finding (#7).
28
+ - Validator: new `episode-sections-missing` error enforces the required
29
+ H2 sections per episode kind (SPEC 5.3) (#8).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Filipp Ignatenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: shelf-spec
3
+ Version: 0.1.0
4
+ Summary: shelf-spec: portable, vendor-neutral agent memory as a git repo of Markdown — spec, validator, thin MCP server and CLI.
5
+ Project-URL: Homepage, https://github.com/ignatenkofi/shelf-spec
6
+ Project-URL: Repository, https://github.com/ignatenkofi/shelf-spec
7
+ Author-email: Filipp Ignatenko <ignatenkofi@gmail.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: agent-memory,git,llm,markdown,mcp,model-context-protocol,spec
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: jsonschema>=4.21
24
+ Requires-Dist: mcp<2,>=1.2.0
25
+ Requires-Dist: pydantic>=2.6
26
+ Requires-Dist: pyyaml>=6.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=8.0; extra == 'dev'
29
+ Requires-Dist: ruff>=0.5.0; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # shelf-spec
33
+
34
+ **shelf-spec** — a portable, vendor-neutral memory format for AI agents —
35
+ plus a thin validator/scaffolder around it.
36
+
37
+ A *shelf* is a git repository of human-readable Markdown: categories, an
38
+ `INDEX.md` catalog, per-category metadata, an optional journal
39
+ (`ledger.tsv`) and policy (`POLICY.md`). Any MCP client attaches the same
40
+ shelf; migration between vendors is `git clone`. The product is the
41
+ **format** ([spec/SPEC.md](spec/SPEC.md)); the reference implementation is
42
+ [docshelf-mcp](https://github.com/ignatenkofi/docshelf-mcp).
43
+
44
+ Status: **v0 (draft, descriptive)** — the spec fixes what already works on
45
+ live shelves. Final name: `shelf-spec` (decided 2026-07-26, ADR 0007; before
46
+ the production repo).
47
+
48
+ ## What is in this repo
49
+
50
+ - `spec/SPEC.md` — shelf-spec v0 (RFC 2119).
51
+ - `spec/shelf.schema.json` — JSON Schema (draft 2020-12) for `shelf.yml`.
52
+ - `spec/examples/` — example manifests (memory, document, reserved multi).
53
+ - `src/shelf_spec/` — engine (manifest loader, validator, scaffolder, info)
54
+ with two thin transports: an MCP server and a CLI.
55
+ - `docs/advisory-ci.md` — drop-in advisory CI stage for shelf repos.
56
+
57
+ ## Install
58
+
59
+ ```bash
60
+ pip install -e '.[dev]'
61
+ ```
62
+
63
+ ## CLI
64
+
65
+ ```bash
66
+ shelf-spec init PATH --name "My shelf" --profile memory --categories topics,research,sessions
67
+ shelf-spec validate [PATH] # human-readable report
68
+ shelf-spec validate --ci [PATH] # machine JSON on stdout, exit 0/1/2
69
+ shelf-spec validate --json [PATH] # JSON report
70
+ shelf-spec validate --manifest CANDIDATE.yml PATH # validate a tree against
71
+ # an external manifest without touching it
72
+ shelf-spec info [PATH] # manifest + index summary for a client
73
+ shelf-spec serve # MCP server on stdio
74
+ ```
75
+
76
+ Exit codes: `0` — shelf conforms (warnings allowed; `--strict` promotes
77
+ warnings to failure), `1` — spec violations (error findings), `2` —
78
+ config-error (manifest missing / unparseable / schema-invalid; checked
79
+ before any rule).
80
+
81
+ The default shelf root is `$SHELF_SPEC_ROOT`, falling back to the current
82
+ directory.
83
+
84
+ ## MCP server
85
+
86
+ Three tools, same engine as the CLI:
87
+
88
+ | tool | type | what it does |
89
+ |---|---|---|
90
+ | `shelf_init` | write (local) | scaffold a shelf: `shelf.yml`, docs root and categories, `POLICY.md` stub, `.gitignore`; idempotent |
91
+ | `shelf_validate` | read | lint a shelf against the spec; report with findings and severities |
92
+ | `shelf_info` | read | manifest + index summary for a connecting client |
93
+
94
+ Tools take flat keyword arguments — a hand-written `tools/call` looks like
95
+ `{"name": "shelf_validate", "arguments": {"shelf_path": "/path/to/shelf"}}`,
96
+ no wrapper object.
97
+
98
+ Client configuration (stdio):
99
+
100
+ ```json
101
+ {
102
+ "mcpServers": {
103
+ "shelf-spec": {
104
+ "command": "shelf-spec",
105
+ "args": ["serve"],
106
+ "env": { "SHELF_SPEC_ROOT": "/path/to/your/shelf" }
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ Validation and info never scaffold a shelf silently: pointing them at a
113
+ directory without a manifest is a config-error, not an invitation to
114
+ create one.
115
+
116
+ ## Compatibility promise
117
+
118
+ An existing docshelf/memshelf shelf becomes spec-conformant by adding
119
+ **one file** — `shelf.yml` with `mode: single`. Nothing is migrated
120
+ (ADR-0005). `.docshelf.json` remains a legal implementation detail;
121
+ `shelf.yml` is the contract. Ready-to-apply manifests for the shelves
122
+ named in the roadmap live in [`docs/adoption/`](docs/adoption/README.md).
123
+
124
+ ## License
125
+
126
+ MIT.
@@ -0,0 +1,95 @@
1
+ # shelf-spec
2
+
3
+ **shelf-spec** — a portable, vendor-neutral memory format for AI agents —
4
+ plus a thin validator/scaffolder around it.
5
+
6
+ A *shelf* is a git repository of human-readable Markdown: categories, an
7
+ `INDEX.md` catalog, per-category metadata, an optional journal
8
+ (`ledger.tsv`) and policy (`POLICY.md`). Any MCP client attaches the same
9
+ shelf; migration between vendors is `git clone`. The product is the
10
+ **format** ([spec/SPEC.md](spec/SPEC.md)); the reference implementation is
11
+ [docshelf-mcp](https://github.com/ignatenkofi/docshelf-mcp).
12
+
13
+ Status: **v0 (draft, descriptive)** — the spec fixes what already works on
14
+ live shelves. Final name: `shelf-spec` (decided 2026-07-26, ADR 0007; before
15
+ the production repo).
16
+
17
+ ## What is in this repo
18
+
19
+ - `spec/SPEC.md` — shelf-spec v0 (RFC 2119).
20
+ - `spec/shelf.schema.json` — JSON Schema (draft 2020-12) for `shelf.yml`.
21
+ - `spec/examples/` — example manifests (memory, document, reserved multi).
22
+ - `src/shelf_spec/` — engine (manifest loader, validator, scaffolder, info)
23
+ with two thin transports: an MCP server and a CLI.
24
+ - `docs/advisory-ci.md` — drop-in advisory CI stage for shelf repos.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pip install -e '.[dev]'
30
+ ```
31
+
32
+ ## CLI
33
+
34
+ ```bash
35
+ shelf-spec init PATH --name "My shelf" --profile memory --categories topics,research,sessions
36
+ shelf-spec validate [PATH] # human-readable report
37
+ shelf-spec validate --ci [PATH] # machine JSON on stdout, exit 0/1/2
38
+ shelf-spec validate --json [PATH] # JSON report
39
+ shelf-spec validate --manifest CANDIDATE.yml PATH # validate a tree against
40
+ # an external manifest without touching it
41
+ shelf-spec info [PATH] # manifest + index summary for a client
42
+ shelf-spec serve # MCP server on stdio
43
+ ```
44
+
45
+ Exit codes: `0` — shelf conforms (warnings allowed; `--strict` promotes
46
+ warnings to failure), `1` — spec violations (error findings), `2` —
47
+ config-error (manifest missing / unparseable / schema-invalid; checked
48
+ before any rule).
49
+
50
+ The default shelf root is `$SHELF_SPEC_ROOT`, falling back to the current
51
+ directory.
52
+
53
+ ## MCP server
54
+
55
+ Three tools, same engine as the CLI:
56
+
57
+ | tool | type | what it does |
58
+ |---|---|---|
59
+ | `shelf_init` | write (local) | scaffold a shelf: `shelf.yml`, docs root and categories, `POLICY.md` stub, `.gitignore`; idempotent |
60
+ | `shelf_validate` | read | lint a shelf against the spec; report with findings and severities |
61
+ | `shelf_info` | read | manifest + index summary for a connecting client |
62
+
63
+ Tools take flat keyword arguments — a hand-written `tools/call` looks like
64
+ `{"name": "shelf_validate", "arguments": {"shelf_path": "/path/to/shelf"}}`,
65
+ no wrapper object.
66
+
67
+ Client configuration (stdio):
68
+
69
+ ```json
70
+ {
71
+ "mcpServers": {
72
+ "shelf-spec": {
73
+ "command": "shelf-spec",
74
+ "args": ["serve"],
75
+ "env": { "SHELF_SPEC_ROOT": "/path/to/your/shelf" }
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ Validation and info never scaffold a shelf silently: pointing them at a
82
+ directory without a manifest is a config-error, not an invitation to
83
+ create one.
84
+
85
+ ## Compatibility promise
86
+
87
+ An existing docshelf/memshelf shelf becomes spec-conformant by adding
88
+ **one file** — `shelf.yml` with `mode: single`. Nothing is migrated
89
+ (ADR-0005). `.docshelf.json` remains a legal implementation detail;
90
+ `shelf.yml` is the contract. Ready-to-apply manifests for the shelves
91
+ named in the roadmap live in [`docs/adoption/`](docs/adoption/README.md).
92
+
93
+ ## License
94
+
95
+ MIT.
@@ -0,0 +1,12 @@
1
+ # ADR-индекс пакета 07 (shelf-spec, ранее openshelf)
2
+
3
+ Все решения в статусе `proposed` до старта реализации (HANDOFF-паттерн полки).
4
+
5
+ | ADR | Решение |
6
+ |---|---|
7
+ | [0001](0001-spec-first-not-another-memory-store.md) | Спек-первичность: формат — продукт, сервер — референс; не ещё один memory-store |
8
+ | [0002](0002-git-native-concurrency-advisory-leases.md) | Git-native конкурентность + advisory-леазы; не lock-сервер, не CRDT |
9
+ | [0003](0003-memory-is-data-not-instructions.md) | «Память — данные, не инструкции» как требование протокола (анти-poisoning) |
10
+ | [0004](0004-zones-roles-dual-enforcement.md) | Зоны/роли в `agents.yml`, двухплоскостной enforcement (сервер + линт при мёрже) |
11
+ | [0005](0005-extract-spec-from-existing-shelves.md) | Спек извлекается из docshelf/memshelf; они — reference, ничего не переписываем |
12
+ | [0006](0006-byom-no-vendor-memory-sync.md) | BYOM: вендорскую память не синхронизируем — полка её заменяет |
@@ -0,0 +1,41 @@
1
+ # Adoption kit — shelf.yml candidates for the owner's shelves
2
+
3
+ Ready-to-apply `shelf.yml` manifests for the three existing shelves named
4
+ in the M0 roadmap. Each one makes its shelf spec-conformant by adding a
5
+ single file (`mode: single`, compatibility promise of ADR-0005) — nothing
6
+ else migrates.
7
+
8
+ | candidate | target shelf | profile | notes |
9
+ |---|---|---|---|
10
+ | `sqst-memshelf.shelf.yml` | sqst-memshelf | memory | ledger + policy declared |
11
+ | `unevie-shelf.shelf.yml` | unevie-shelf | document | older `.docshelf.json` stays valid |
12
+ | `homelab-shelf.shelf.yml` | homelab-shelf | document | pre-docshelf: nested docs root, external index, extra dirs |
13
+
14
+ All three validate green (`exit 0`, zero error findings) against the live
15
+ clones via the external-manifest mode, which needs no write access to the
16
+ shelf:
17
+
18
+ ```bash
19
+ shelf-spec validate --ci --manifest docs/adoption/<shelf>.shelf.yml /path/to/<shelf>
20
+ ```
21
+
22
+ ## Status: drafted, not yet applied
23
+
24
+ Committing these files **into the shelf repositories is an owner action**
25
+ — the shelf repos are outside this repository and were treated as
26
+ read-only during M0. Until then this directory is the canonical home of
27
+ the candidates (they must not live only in a session handoff). To apply:
28
+
29
+ 1. Copy the candidate to the shelf root as `shelf.yml`
30
+ (drop the `<shelf>.` prefix).
31
+ 2. Run `shelf-spec validate --ci .` in the shelf root — expect exit 0.
32
+ 3. Commit; optionally add the advisory CI stage from
33
+ [`../advisory-ci.md`](../advisory-ci.md) in the same change.
34
+
35
+ Expected non-blocking findings on today's clones (exit code stays 0):
36
+ sqst-memshelf — none; unevie-shelf — `remote-mismatch` warning,
37
+ `no-policy` info; homelab-shelf — `remote-mismatch` and one `stale-index`
38
+ warning, `no-policy` info.
39
+
40
+ Once the candidate is merged as `shelf.yml`, delete it from this
41
+ directory — the shelf's own copy becomes the source of truth.
@@ -0,0 +1,93 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "shelf-spec"
7
+ dynamic = ["version"]
8
+ description = "shelf-spec: portable, vendor-neutral agent memory as a git repo of Markdown — spec, validator, thin MCP server and CLI."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Filipp Ignatenko", email = "ignatenkofi@gmail.com" }
14
+ ]
15
+ keywords = ["mcp", "model-context-protocol", "agent-memory", "markdown", "git", "spec", "llm"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ "Topic :: Text Processing :: Markup :: Markdown",
28
+ ]
29
+
30
+ dependencies = [
31
+ # mcp 2.0.0 removed mcp.server.fastmcp — pin the SDK by major.
32
+ "mcp>=1.2.0,<2",
33
+ "pydantic>=2.6",
34
+ "pyyaml>=6.0",
35
+ "jsonschema>=4.21",
36
+ ]
37
+
38
+ [project.optional-dependencies]
39
+ dev = [
40
+ "pytest>=8.0",
41
+ "ruff>=0.5.0",
42
+ ]
43
+
44
+ [project.scripts]
45
+ shelf-spec = "shelf_spec.cli:main"
46
+
47
+ [project.urls]
48
+ Homepage = "https://github.com/ignatenkofi/shelf-spec"
49
+ Repository = "https://github.com/ignatenkofi/shelf-spec"
50
+
51
+ [tool.hatch.version]
52
+ path = "src/shelf_spec/__init__.py"
53
+
54
+ [tool.hatch.build.targets.wheel]
55
+ packages = ["src/shelf_spec"]
56
+
57
+ [tool.hatch.build.targets.wheel.force-include]
58
+ # The canonical schema lives in spec/ (single source of truth); ship a copy
59
+ # inside the wheel so the installed package can validate manifests offline.
60
+ "spec/shelf.schema.json" = "shelf_spec/spec/shelf.schema.json"
61
+
62
+ [tool.hatch.build.targets.sdist]
63
+ include = [
64
+ "src/",
65
+ "tests/",
66
+ "spec/",
67
+ "README.md",
68
+ "LICENSE",
69
+ "CHANGELOG.md",
70
+ "pyproject.toml",
71
+ ]
72
+
73
+ [tool.pytest.ini_options]
74
+ testpaths = ["tests"]
75
+ addopts = "-ra --strict-markers"
76
+
77
+ [tool.ruff]
78
+ line-length = 100
79
+ target-version = "py310"
80
+
81
+ [tool.ruff.lint]
82
+ select = [
83
+ "E", # pycodestyle errors
84
+ "W", # pycodestyle warnings
85
+ "F", # pyflakes
86
+ "I", # isort
87
+ "B", # flake8-bugbear
88
+ "UP", # pyupgrade
89
+ ]
90
+ ignore = ["E501"] # line too long — handled by formatter
91
+
92
+ [tool.ruff.lint.isort]
93
+ known-first-party = ["shelf_spec"]