benchweave-sdk 0.0.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 (88) hide show
  1. benchweave_sdk-0.0.1/.gitignore +17 -0
  2. benchweave_sdk-0.0.1/LICENSE +21 -0
  3. benchweave_sdk-0.0.1/PKG-INFO +192 -0
  4. benchweave_sdk-0.0.1/README.md +174 -0
  5. benchweave_sdk-0.0.1/hatch_build.py +74 -0
  6. benchweave_sdk-0.0.1/pyproject.toml +55 -0
  7. benchweave_sdk-0.0.1/src/benchweave_sdk/__init__.py +8 -0
  8. benchweave_sdk-0.0.1/src/benchweave_sdk/cli.py +361 -0
  9. benchweave_sdk-0.0.1/src/benchweave_sdk/conformance.py +63 -0
  10. benchweave_sdk-0.0.1/src/benchweave_sdk/console.py +57 -0
  11. benchweave_sdk-0.0.1/src/benchweave_sdk/fixtures.py +289 -0
  12. benchweave_sdk-0.0.1/src/benchweave_sdk/interfaces.py +51 -0
  13. benchweave_sdk-0.0.1/src/benchweave_sdk/packaging.py +61 -0
  14. benchweave_sdk-0.0.1/src/benchweave_sdk/presentation.py +404 -0
  15. benchweave_sdk-0.0.1/src/benchweave_sdk/preview_assets/inventory.json +21 -0
  16. benchweave_sdk-0.0.1/src/benchweave_sdk/preview_assets/site/assets/index-BqP_aR5c.css +1 -0
  17. benchweave_sdk-0.0.1/src/benchweave_sdk/preview_assets/site/assets/index-D0qT06Ho.js +28 -0
  18. benchweave_sdk-0.0.1/src/benchweave_sdk/preview_assets/site/index.html +14 -0
  19. benchweave_sdk-0.0.1/src/benchweave_sdk/preview_models.py +103 -0
  20. benchweave_sdk-0.0.1/src/benchweave_sdk/preview_server.py +305 -0
  21. benchweave_sdk-0.0.1/src/benchweave_sdk/preview_tui.py +69 -0
  22. benchweave_sdk-0.0.1/src/benchweave_sdk/py.typed +1 -0
  23. benchweave_sdk-0.0.1/src/benchweave_sdk/scaffold.py +430 -0
  24. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/_GENERATED.txt +12 -0
  25. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/bench.schema.json +476 -0
  26. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/commissioning.schema.json +277 -0
  27. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/examples/bench.json +158 -0
  28. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/examples/commissioning.json +158 -0
  29. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/examples/procedure.json +101 -0
  30. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/examples/run-binding.json +38 -0
  31. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/examples/run-record.json +25 -0
  32. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/examples/safety-policy.json +110 -0
  33. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/procedure.schema.json +498 -0
  34. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/run-binding.schema.json +176 -0
  35. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/run-record.schema.json +321 -0
  36. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/execution/execution-v1.0.0/safety-policy.schema.json +511 -0
  37. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/interface/_GENERATED.txt +6 -0
  38. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/interface/interface-v1.1.1/examples/mcp-start-exchange.json +63 -0
  39. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/interface/interface-v1.1.1/examples/operation-vectors.json +393 -0
  40. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/interface/interface-v1.1.1/interface.schema.json +1974 -0
  41. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/interface/interface-v1.1.1/mcp-tools.json +25151 -0
  42. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/interface/interface-v1.1.1/openapi.json +3584 -0
  43. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/interface/interface-v1.1.1/operation-catalog.json +1448 -0
  44. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/_GENERATED.txt +24 -0
  45. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/device-profile-catalog.json +4798 -0
  46. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/device-profile-catalog.schema.json +110 -0
  47. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-action-vectors.json +2678 -0
  48. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-daq.json +177 -0
  49. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-dc_psu.json +159 -0
  50. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-dmm.json +144 -0
  51. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-electronic_load.json +159 -0
  52. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-embedded_controller.json +186 -0
  53. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-function_generator.json +155 -0
  54. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-logic_analyser.json +188 -0
  55. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-oscilloscope.json +177 -0
  56. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-smu.json +214 -0
  57. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-spectrum_analyser.json +177 -0
  58. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-switch_matrix.json +154 -0
  59. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/class-vna.json +177 -0
  60. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/measurement-vectors.json +1089 -0
  61. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/reference-can.json +108 -0
  62. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/reference-capture.json +114 -0
  63. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/reference-controller.json +150 -0
  64. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/reference-psu.json +187 -0
  65. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/examples/reference-vectors.json +259 -0
  66. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/otdp-device-descriptor.schema.json +3003 -0
  67. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/otdp-measurement.schema.json +787 -0
  68. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/otdp/otdp-v0.3.0/otdp-runtime.schema.json +1238 -0
  69. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/plugin-ui/_GENERATED.txt +5 -0
  70. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/plugin-ui/contracts.py +573 -0
  71. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/plugin-ui/plugin-ui-v0.1.0/binding-catalogue.schema.json +6 -0
  72. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/plugin-ui/plugin-ui-v0.1.0/configuration-preset.schema.json +6 -0
  73. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/plugin-ui/plugin-ui-v0.1.0/presentation-envelope.schema.json +6 -0
  74. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/plugin-ui/plugin-ui-v0.1.0/ui-manifest.schema.json +69 -0
  75. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/plugin-ui-preview/_GENERATED.txt +2 -0
  76. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/plugin-ui-preview/plugin-ui-preview-v1/fixture.schema.json +94 -0
  77. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/plugin-ui-preview/plugin-ui-preview-v1/preview-document.schema.json +209 -0
  78. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/registry/_GENERATED.txt +6 -0
  79. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/registry/registry-v1.0.0/examples/package-lock.json +32 -0
  80. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/registry/registry-v1.0.0/examples/release-manifest.json +170 -0
  81. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/registry/registry-v1.0.0/examples/release-status.json +18 -0
  82. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/registry/registry-v1.0.0/package-lock.schema.json +116 -0
  83. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/registry/registry-v1.0.0/release-manifest.schema.json +721 -0
  84. benchweave_sdk-0.0.1/src/benchweave_sdk/standards/registry/registry-v1.0.0/release-status.schema.json +190 -0
  85. benchweave_sdk-0.0.1/src/benchweave_sdk/standards_sync.py +270 -0
  86. benchweave_sdk-0.0.1/src/benchweave_sdk/testing.py +106 -0
  87. benchweave_sdk-0.0.1/src/benchweave_sdk/validation.py +102 -0
  88. benchweave_sdk-0.0.1/standards-lock.json +1 -0
@@ -0,0 +1,17 @@
1
+ __pycache__/
2
+ .gortex/
3
+ venv/
4
+ uv.lock
5
+ docs/superpowers/
6
+
7
+ # Memory-proposal ledger: session findings queued for the vault (see .claude/memory-protocol.md)
8
+ .claude/memory-proposals.jsonl
9
+ .claude/memory-proposals.jsonl.tmp
10
+ .claude/memory-proposals.drained.jsonl
11
+ .claude/memory-proposals.deadletter.jsonl
12
+ .claude/memory-proposals.lock
13
+ .claude/memory-drain-receipt.json
14
+ .claude/memory-drain-receipt.json.tmp
15
+ .claude/memory-drain-receipts.jsonl
16
+ .claude/memory-drain-receipts.jsonl.tmp
17
+ .claude/settings.local.json
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 madeinoz67
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,192 @@
1
+ Metadata-Version: 2.5
2
+ Name: benchweave-sdk
3
+ Version: 0.0.1
4
+ Summary: Offline authoring and conformance tools for BenchWeave OTDP device plugins.
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.13
8
+ Requires-Dist: click<9,>=8.3
9
+ Requires-Dist: jsonschema>=4.23
10
+ Requires-Dist: referencing>=0.35
11
+ Requires-Dist: rfc3339-validator>=0.1.4
12
+ Requires-Dist: rfc3987>=1.3.8
13
+ Requires-Dist: rich<15,>=14
14
+ Requires-Dist: textual<9,>=8.2
15
+ Provides-Extra: test
16
+ Requires-Dist: pytest>=8.0; extra == 'test'
17
+ Description-Content-Type: text/markdown
18
+
19
+ ![BenchWeave SDK — Build. Validate. Integrate. A plugin package moving through build and validation into the BenchWeave gateway and connected instruments.](docs/assets/benchweave-sdk-banner.png)
20
+
21
+ # BenchWeave plugin developer SDK
22
+
23
+ Build an external device plugin without importing gateway internals. Python 3.13+, SDK 0.0.1, OTDP 0.3.0 and adapter API 1.1 are the initial baseline. This package is a separate wheel built alongside BenchWeave; published to PyPI as benchweave-sdk.
24
+
25
+ ## Sister repository
26
+
27
+ This is the SDK. The BenchWeave gateway and the canonical architecture and contract standards live in the main repository: [madeinoz67/benchweave](https://github.com/madeinoz67/benchweave). This SDK is mounted there at `packages/sdk` as a git submodule and has its own CI and release cycle.
28
+
29
+ ## Installation
30
+
31
+ Stable releases are on PyPI:
32
+
33
+ ```sh
34
+ pip install benchweave-sdk
35
+ # or as an isolated CLI tool
36
+ uv tool install benchweave-sdk
37
+ # or via Homebrew (macOS and Linux)
38
+ brew install madeinoz67/tap/benchweave-sdk
39
+ ```
40
+
41
+ For bleeding-edge work before a release, install straight from the default branch:
42
+
43
+ ```sh
44
+ pip install git+https://github.com/madeinoz67/benchweave-sdk.git
45
+ ```
46
+
47
+ To hack on the SDK itself, clone the repository and `uv sync --extra test`.
48
+
49
+ ## Five steps
50
+
51
+ 1. Install the SDK from PyPI (`uv pip install benchweave-sdk`, or see [Installation](#installation)).
52
+ 2. Run `benchweave-sdk new plugins/acme/model100 --package benchweave_acme_model100`. Replace `acme/model100` with your manufacturer/device name; the independent project contains `src/benchweave_acme_model100/` and `tests/`.
53
+ 3. Change into the generated project (`cd plugins/acme/model100`). Replace the explicitly synthetic protocol with verified device behaviour, then update its descriptor. The generated AI-GUIDE.md describes the design, build, test, review and release steps.
54
+ 4. Install the plugin with test dependencies, run its tests, and run `benchweave-sdk check src/benchweave_acme_model100/descriptor.json`. Record all applicable S01–S18, C01–C12 and M01–M14 obligations and evidence; basic SDK checks do not cover all of them.
55
+ 5. Build with `uv build`, prepare registry metadata and reviewed evidence, and approve the release before publication or hardware qualification. `benchweave-sdk inventory` helps generate hashes, not a complete registry manifest.
56
+
57
+ The generated runtime has no dependency on this SDK. The plugin test extra pins the SDK version from PyPI. Generate and retain a plugin dependency lock in its repository. A template is not qualified firmware or a real instrument driver.
58
+
59
+ ## Directory structure
60
+
61
+ In a plugin collection, each device plugin is an independent project at `plugins/<manufacturer>/<name>/`. The SDK itself stays in `packages/sdk/`. An external plugin repository can use that device project as its repository root; it does not need the enclosing `plugins/<manufacturer>/` directories. The project directory and Python import package have different roles: `acme/model100` organises the collection, while `benchweave_acme_model100` is the import name selected by `--package`.
62
+
63
+ Create a project from the collection root:
64
+
65
+ ```sh
66
+ benchweave-sdk new plugins/acme/model100 --package benchweave_acme_model100 --with-ui
67
+ cd plugins/acme/model100
68
+ ```
69
+
70
+ The destination must not already exist. Omit `--with-ui` for a plugin without presentation metadata.
71
+
72
+ ```text
73
+ plugins/acme/model100/ # independent plugin project
74
+ ├── pyproject.toml # build configuration and test dependencies
75
+ ├── README.md
76
+ ├── AI-GUIDE.md # generated development workflow
77
+ ├── UI-GUIDE.md # generated only with --with-ui
78
+ ├── docs/ # author-supplied device documentation
79
+ │ ├── compatibility.md # supported models/firmware and limitations
80
+ │ └── qualification.md # supervised hardware test plan/evidence
81
+ ├── firmware/ # optional author-supplied firmware material
82
+ │ ├── README.md # official sources, versions and checksums
83
+ │ └── release-notes/ # relevant vendor changes and upgrade constraints
84
+ ├── src/
85
+ │ └── benchweave_acme_model100/ # import package; included in the wheel
86
+ │ ├── __init__.py
87
+ │ ├── adapter.py # SDK-facing adapter and create_plugin
88
+ │ ├── protocol.py # device protocol implementation
89
+ │ ├── descriptor.json # OTDP device/operation contract
90
+ │ ├── protocol.md # protocol evidence, initially synthetic
91
+ │ ├── vectors.json # exact exchanges, initially synthetic
92
+ │ ├── config/ # optional configuration for a headless plugin
93
+ │ │ ├── settings.schema.json # author-supplied complete-settings schema
94
+ │ │ └── presets/
95
+ │ │ └── default.json # author-supplied configuration preset
96
+ │ ├── presentation.json # --with-ui: envelope and resource root
97
+ │ ├── binding-catalogue.json # --with-ui: descriptor-aligned targets
98
+ │ └── ui/ # --with-ui: presentation resource root
99
+ │ ├── manifest.json # generated readings page; no plot required
100
+ │ ├── fixtures/ # generated synthetic preview examples
101
+ │ │ ├── normal.json
102
+ │ │ └── warning.json
103
+ │ ├── settings/ # author-supplied, when configuration exists
104
+ │ │ └── settings.schema.json
105
+ │ ├── presets/ # author-supplied complete configurations
106
+ │ │ └── default.json
107
+ │ └── assets/ # author-supplied declared static resources
108
+ └── tests/
109
+ ├── test_plugin.py # generated mock/conformance tests
110
+ ├── test_presentation_preview.py # generated offline preview conformance test
111
+ ├── test_configuration.py # author-supplied schema/preset checks
112
+ ├── test_presentation.py # author-supplied UI binding/asset checks
113
+ └── fixtures/ # author-supplied exchanges by model/firmware
114
+ ```
115
+
116
+ The SDK generates `ui/manifest.json`, schema-valid synthetic examples under `ui/fixtures/`, and `tests/test_presentation_preview.py`. The `docs/`, `firmware/`, `config/`, optional UI asset directories and additional test files remain author-supplied extensions. Add only the features the device plugin supports. `default.json` is an example filename, not an automatically selected or applied configuration.
117
+
118
+ | Optional feature | Recommended location | Behaviour and ownership |
119
+ | --- | --- | --- |
120
+ | Device configuration without UI | `src/<package>/config/settings.schema.json` and `config/presets/` | Validate complete settings offline with `check-preset`; application requires an approved device procedure. |
121
+ | Device configuration shown in UI | `src/<package>/ui/settings/` and `ui/presets/` | Keep one authoritative copy inside the UI resource root and declare it in the manifest; do not duplicate it under `config/`. |
122
+ | Specialised pages and optional graphs | `src/<package>/ui/manifest.json` and `ui/assets/` | Declare bindings, plot metadata and supported panel IDs. A page need not have a graph. Browser rendering remains separate work. |
123
+ | Data collection | Descriptor action/measurement contracts, adapter code and `tests/fixtures/` | Declare supported acquisition and dataset bindings. The gateway owns execution and retained data; live datasets are not packaged here. |
124
+ | Firmware compatibility | `docs/compatibility.md`, descriptor firmware constraints and firmware-specific test fixtures | State supported firmware versions and retain evidence. The descriptor remains the runtime compatibility contract. |
125
+ | Firmware reference material | `firmware/README.md` and `firmware/release-notes/` | Record vendor sources, exact version/checksum information and upgrade constraints. This directory has no SDK discovery or flashing behaviour. Redistribute vendor images only when permitted and explicitly required by the release. |
126
+ | Hardware qualification | `docs/qualification.md` | Record the supervised test plan, tested versions and evidence. Synthetic tests do not establish hardware qualification. |
127
+
128
+ A preset contains complete settings and compatibility/provenance metadata, not collected measurements. A plugin can have configuration without UI, UI without configuration, and firmware compatibility declarations without shipping firmware images.
129
+
130
+ Keep distributable resources inside `src/<package>/` so the generated Hatch wheel configuration includes them. Generate and retain `uv.lock` for development dependencies, and supply the appropriate licence and release evidence before distribution; these are not scaffolded. Build outputs belong in `dist/`. Gateway configuration, credentials, live readings and retained datasets belong to the deployment/runtime stores, outside the plugin source package.
131
+
132
+ ### Path resolution and validation
133
+
134
+ Run these commands from the plugin project root after installing its development dependencies:
135
+
136
+ ```sh
137
+ benchweave-sdk check src/benchweave_acme_model100/descriptor.json
138
+ benchweave-sdk check-ui src/benchweave_acme_model100/presentation.json \
139
+ --descriptor src/benchweave_acme_model100/descriptor.json \
140
+ --resources src/benchweave_acme_model100 \
141
+ --catalogue src/benchweave_acme_model100/binding-catalogue.json \
142
+ --firmware 1.0.0
143
+ pytest
144
+ uv build
145
+ ```
146
+
147
+ Here `--resources` points to the **package root**. The generated envelope's `resource_root: "ui"` selects its `ui/` subdirectory. Manifest asset paths such as `settings/settings.schema.json` and `presets/default.json` are relative to that UI root. Resource paths must remain inside the root and cannot traverse symlinks; use canonical local paths. On macOS, use `/private/tmp/...` rather than the `/tmp` symlink for temporary preview projects. Keep descriptor, manifest and asset byte hashes current after editing resources. The binding catalogue must be aligned with the descriptor and verified by the host during admission; a packaged candidate catalogue does not grant device capabilities.
148
+
149
+ ## Optional plugin pages and presets
150
+
151
+ Add `--with-ui` to `benchweave-sdk new` to generate a declarative readings page, presentation envelope and binding catalogue. The default scaffold stays unchanged. Keep presentation assets under the import package's `ui/` directory so wheels carry them; store complete configuration presets alongside their settings schema. Plugins can declare configuration, readings, dataset and registered panel pages, with plots only when appropriate.
152
+
153
+ Use `benchweave-sdk check-ui` and `benchweave-sdk check-preset` for offline validation before packaging. Validation neither admits a plugin nor approves applying settings. The [plugin presentation guide](https://github.com/madeinoz67/benchweave/blob/main/docs/plugin-ui-v0.1.0/README.md) (main repository) covers the directory structure, preconfigured settings, optional graphs, data bindings and CLI examples.
154
+
155
+ ### Local UI preview
156
+
157
+ The SDK includes the version-matched React renderer and nine deterministic baseline scenarios. Preview author fixtures without importing plugin Python, opening a device transport or contacting a gateway:
158
+
159
+ ```sh
160
+ benchweave-sdk preview-ui src/benchweave_acme_model100/presentation.json \
161
+ --descriptor src/benchweave_acme_model100/descriptor.json \
162
+ --resources src/benchweave_acme_model100 \
163
+ --catalogue src/benchweave_acme_model100/binding-catalogue.json \
164
+ --fixtures src/benchweave_acme_model100/ui/fixtures
165
+ ```
166
+
167
+ Use `--no-open` for CI or a terminal-only readiness check. The default listener is an ephemeral port on `127.0.0.1`; wildcard listeners are rejected. A non-loopback host requires `--allow-network` and remains unsuitable for shared or production deployment. UI contributors can point at a compatible Vite renderer with `--renderer-url`; the CLI adds the preview server URL as the renderer's `apiBase` query parameter and permits cross-origin API responses only for that renderer's exact origin. Both renderers require preview API version 1.
168
+
169
+ The command suite uses Click for stable parsing and exit codes and Rich for readable non-interactive output. In an interactive terminal, `preview-ui` uses a Textual status screen: press `o` to reopen the browser and `q` to stop the preview. Textual is deliberately bypassed for `--no-open` and non-terminal output so CI, pipes and SDK tests remain deterministic.
170
+
171
+ Every preview is labelled `SIMULATED PRESENTATION DATA`. Control interactions create only in-memory simulated receipts and never update observed readings optimistically. Preview success is not admission, hardware qualification or permission to operate equipment.
172
+
173
+ ## Public surfaces
174
+
175
+ - `interfaces`: structural async `Adapter`, `HostServices`, `OperationContext` and optional `CaptureServices` definitions. No SDK superclass is required.
176
+ - `testing`: deterministic `MockContext` and `MockHost`, exact scripted transfers, dispatch markers, cancellation and a manually advanced clock. These are test doubles, not qualified host services.
177
+ - `validation`: pinned local schemas, strict finite JSON, format validation, runtime correlation and basic descriptor S01/S02 checks. Unresolved schema references fail without network retrieval.
178
+ - `conformance`: reusable operation and quiet lifecycle checks, with configurable wall-clock timeouts for cooperative async calls. Authors must add device-specific failure, profile and measurement tests. Use process isolation for blocking code or code that suppresses cancellation.
179
+ - `presentation`: bounded offline validation of presentation resources and complete configuration presets, using the same validator bytes as the gateway.
180
+ - `packaging`: inventory and integrity checks for a prepared bundle, including duplicate/path/symlink rejection. No installation, signing, publication or dependency execution.
181
+
182
+ ## Compatibility and limits
183
+
184
+ The gateway has an explicit OTDP bridge and loader for identify, scalar read and scalar write. Profile actions, capture and streaming are not implemented by that bridge. Package-relative and standard-library imports are supported; arbitrary third-party runtime dependencies need further integration. Existing simulator interfaces remain private. Release CI builds an SDK and external plugin outside the checkout and exercises that plugin through the gateway bridge using mock transport. Unsupported operations must fail explicitly. No live install endpoint, physical backend, container device permissions or hardware qualification is supplied by this SDK.
185
+
186
+ The SDK sdist and wheel include the canonical OTDP, registry and plugin presentation contract sets. Build from the repository with `uv build packages/sdk`; the build hook includes contract resources and a wheel rebuilt from the sdist remains self-contained. The release smoke compares installed contract bytes with the canonical repository copies. SDK and gateway versions are independently named; each release must record the exact pair tested before expanding compatibility claims.
187
+
188
+ Pure Python plugins still need declared dependencies and compatible runtimes. Native dependencies and physical transport mappings require a separately qualified gateway deployment. The SDK does not install dependencies into a running gateway.
189
+
190
+ ## Distribution rights
191
+
192
+ The SDK package is distributed under the [MIT licence](LICENSE). The vendored OTDP, registry and presentation contract sets and the generated templates are part of this package and carry the same grant. Plugin authors choose their own licence; generated examples contain no licence grant and make no claim on plugin code written with them.
@@ -0,0 +1,174 @@
1
+ ![BenchWeave SDK — Build. Validate. Integrate. A plugin package moving through build and validation into the BenchWeave gateway and connected instruments.](docs/assets/benchweave-sdk-banner.png)
2
+
3
+ # BenchWeave plugin developer SDK
4
+
5
+ Build an external device plugin without importing gateway internals. Python 3.13+, SDK 0.0.1, OTDP 0.3.0 and adapter API 1.1 are the initial baseline. This package is a separate wheel built alongside BenchWeave; published to PyPI as benchweave-sdk.
6
+
7
+ ## Sister repository
8
+
9
+ This is the SDK. The BenchWeave gateway and the canonical architecture and contract standards live in the main repository: [madeinoz67/benchweave](https://github.com/madeinoz67/benchweave). This SDK is mounted there at `packages/sdk` as a git submodule and has its own CI and release cycle.
10
+
11
+ ## Installation
12
+
13
+ Stable releases are on PyPI:
14
+
15
+ ```sh
16
+ pip install benchweave-sdk
17
+ # or as an isolated CLI tool
18
+ uv tool install benchweave-sdk
19
+ # or via Homebrew (macOS and Linux)
20
+ brew install madeinoz67/tap/benchweave-sdk
21
+ ```
22
+
23
+ For bleeding-edge work before a release, install straight from the default branch:
24
+
25
+ ```sh
26
+ pip install git+https://github.com/madeinoz67/benchweave-sdk.git
27
+ ```
28
+
29
+ To hack on the SDK itself, clone the repository and `uv sync --extra test`.
30
+
31
+ ## Five steps
32
+
33
+ 1. Install the SDK from PyPI (`uv pip install benchweave-sdk`, or see [Installation](#installation)).
34
+ 2. Run `benchweave-sdk new plugins/acme/model100 --package benchweave_acme_model100`. Replace `acme/model100` with your manufacturer/device name; the independent project contains `src/benchweave_acme_model100/` and `tests/`.
35
+ 3. Change into the generated project (`cd plugins/acme/model100`). Replace the explicitly synthetic protocol with verified device behaviour, then update its descriptor. The generated AI-GUIDE.md describes the design, build, test, review and release steps.
36
+ 4. Install the plugin with test dependencies, run its tests, and run `benchweave-sdk check src/benchweave_acme_model100/descriptor.json`. Record all applicable S01–S18, C01–C12 and M01–M14 obligations and evidence; basic SDK checks do not cover all of them.
37
+ 5. Build with `uv build`, prepare registry metadata and reviewed evidence, and approve the release before publication or hardware qualification. `benchweave-sdk inventory` helps generate hashes, not a complete registry manifest.
38
+
39
+ The generated runtime has no dependency on this SDK. The plugin test extra pins the SDK version from PyPI. Generate and retain a plugin dependency lock in its repository. A template is not qualified firmware or a real instrument driver.
40
+
41
+ ## Directory structure
42
+
43
+ In a plugin collection, each device plugin is an independent project at `plugins/<manufacturer>/<name>/`. The SDK itself stays in `packages/sdk/`. An external plugin repository can use that device project as its repository root; it does not need the enclosing `plugins/<manufacturer>/` directories. The project directory and Python import package have different roles: `acme/model100` organises the collection, while `benchweave_acme_model100` is the import name selected by `--package`.
44
+
45
+ Create a project from the collection root:
46
+
47
+ ```sh
48
+ benchweave-sdk new plugins/acme/model100 --package benchweave_acme_model100 --with-ui
49
+ cd plugins/acme/model100
50
+ ```
51
+
52
+ The destination must not already exist. Omit `--with-ui` for a plugin without presentation metadata.
53
+
54
+ ```text
55
+ plugins/acme/model100/ # independent plugin project
56
+ ├── pyproject.toml # build configuration and test dependencies
57
+ ├── README.md
58
+ ├── AI-GUIDE.md # generated development workflow
59
+ ├── UI-GUIDE.md # generated only with --with-ui
60
+ ├── docs/ # author-supplied device documentation
61
+ │ ├── compatibility.md # supported models/firmware and limitations
62
+ │ └── qualification.md # supervised hardware test plan/evidence
63
+ ├── firmware/ # optional author-supplied firmware material
64
+ │ ├── README.md # official sources, versions and checksums
65
+ │ └── release-notes/ # relevant vendor changes and upgrade constraints
66
+ ├── src/
67
+ │ └── benchweave_acme_model100/ # import package; included in the wheel
68
+ │ ├── __init__.py
69
+ │ ├── adapter.py # SDK-facing adapter and create_plugin
70
+ │ ├── protocol.py # device protocol implementation
71
+ │ ├── descriptor.json # OTDP device/operation contract
72
+ │ ├── protocol.md # protocol evidence, initially synthetic
73
+ │ ├── vectors.json # exact exchanges, initially synthetic
74
+ │ ├── config/ # optional configuration for a headless plugin
75
+ │ │ ├── settings.schema.json # author-supplied complete-settings schema
76
+ │ │ └── presets/
77
+ │ │ └── default.json # author-supplied configuration preset
78
+ │ ├── presentation.json # --with-ui: envelope and resource root
79
+ │ ├── binding-catalogue.json # --with-ui: descriptor-aligned targets
80
+ │ └── ui/ # --with-ui: presentation resource root
81
+ │ ├── manifest.json # generated readings page; no plot required
82
+ │ ├── fixtures/ # generated synthetic preview examples
83
+ │ │ ├── normal.json
84
+ │ │ └── warning.json
85
+ │ ├── settings/ # author-supplied, when configuration exists
86
+ │ │ └── settings.schema.json
87
+ │ ├── presets/ # author-supplied complete configurations
88
+ │ │ └── default.json
89
+ │ └── assets/ # author-supplied declared static resources
90
+ └── tests/
91
+ ├── test_plugin.py # generated mock/conformance tests
92
+ ├── test_presentation_preview.py # generated offline preview conformance test
93
+ ├── test_configuration.py # author-supplied schema/preset checks
94
+ ├── test_presentation.py # author-supplied UI binding/asset checks
95
+ └── fixtures/ # author-supplied exchanges by model/firmware
96
+ ```
97
+
98
+ The SDK generates `ui/manifest.json`, schema-valid synthetic examples under `ui/fixtures/`, and `tests/test_presentation_preview.py`. The `docs/`, `firmware/`, `config/`, optional UI asset directories and additional test files remain author-supplied extensions. Add only the features the device plugin supports. `default.json` is an example filename, not an automatically selected or applied configuration.
99
+
100
+ | Optional feature | Recommended location | Behaviour and ownership |
101
+ | --- | --- | --- |
102
+ | Device configuration without UI | `src/<package>/config/settings.schema.json` and `config/presets/` | Validate complete settings offline with `check-preset`; application requires an approved device procedure. |
103
+ | Device configuration shown in UI | `src/<package>/ui/settings/` and `ui/presets/` | Keep one authoritative copy inside the UI resource root and declare it in the manifest; do not duplicate it under `config/`. |
104
+ | Specialised pages and optional graphs | `src/<package>/ui/manifest.json` and `ui/assets/` | Declare bindings, plot metadata and supported panel IDs. A page need not have a graph. Browser rendering remains separate work. |
105
+ | Data collection | Descriptor action/measurement contracts, adapter code and `tests/fixtures/` | Declare supported acquisition and dataset bindings. The gateway owns execution and retained data; live datasets are not packaged here. |
106
+ | Firmware compatibility | `docs/compatibility.md`, descriptor firmware constraints and firmware-specific test fixtures | State supported firmware versions and retain evidence. The descriptor remains the runtime compatibility contract. |
107
+ | Firmware reference material | `firmware/README.md` and `firmware/release-notes/` | Record vendor sources, exact version/checksum information and upgrade constraints. This directory has no SDK discovery or flashing behaviour. Redistribute vendor images only when permitted and explicitly required by the release. |
108
+ | Hardware qualification | `docs/qualification.md` | Record the supervised test plan, tested versions and evidence. Synthetic tests do not establish hardware qualification. |
109
+
110
+ A preset contains complete settings and compatibility/provenance metadata, not collected measurements. A plugin can have configuration without UI, UI without configuration, and firmware compatibility declarations without shipping firmware images.
111
+
112
+ Keep distributable resources inside `src/<package>/` so the generated Hatch wheel configuration includes them. Generate and retain `uv.lock` for development dependencies, and supply the appropriate licence and release evidence before distribution; these are not scaffolded. Build outputs belong in `dist/`. Gateway configuration, credentials, live readings and retained datasets belong to the deployment/runtime stores, outside the plugin source package.
113
+
114
+ ### Path resolution and validation
115
+
116
+ Run these commands from the plugin project root after installing its development dependencies:
117
+
118
+ ```sh
119
+ benchweave-sdk check src/benchweave_acme_model100/descriptor.json
120
+ benchweave-sdk check-ui src/benchweave_acme_model100/presentation.json \
121
+ --descriptor src/benchweave_acme_model100/descriptor.json \
122
+ --resources src/benchweave_acme_model100 \
123
+ --catalogue src/benchweave_acme_model100/binding-catalogue.json \
124
+ --firmware 1.0.0
125
+ pytest
126
+ uv build
127
+ ```
128
+
129
+ Here `--resources` points to the **package root**. The generated envelope's `resource_root: "ui"` selects its `ui/` subdirectory. Manifest asset paths such as `settings/settings.schema.json` and `presets/default.json` are relative to that UI root. Resource paths must remain inside the root and cannot traverse symlinks; use canonical local paths. On macOS, use `/private/tmp/...` rather than the `/tmp` symlink for temporary preview projects. Keep descriptor, manifest and asset byte hashes current after editing resources. The binding catalogue must be aligned with the descriptor and verified by the host during admission; a packaged candidate catalogue does not grant device capabilities.
130
+
131
+ ## Optional plugin pages and presets
132
+
133
+ Add `--with-ui` to `benchweave-sdk new` to generate a declarative readings page, presentation envelope and binding catalogue. The default scaffold stays unchanged. Keep presentation assets under the import package's `ui/` directory so wheels carry them; store complete configuration presets alongside their settings schema. Plugins can declare configuration, readings, dataset and registered panel pages, with plots only when appropriate.
134
+
135
+ Use `benchweave-sdk check-ui` and `benchweave-sdk check-preset` for offline validation before packaging. Validation neither admits a plugin nor approves applying settings. The [plugin presentation guide](https://github.com/madeinoz67/benchweave/blob/main/docs/plugin-ui-v0.1.0/README.md) (main repository) covers the directory structure, preconfigured settings, optional graphs, data bindings and CLI examples.
136
+
137
+ ### Local UI preview
138
+
139
+ The SDK includes the version-matched React renderer and nine deterministic baseline scenarios. Preview author fixtures without importing plugin Python, opening a device transport or contacting a gateway:
140
+
141
+ ```sh
142
+ benchweave-sdk preview-ui src/benchweave_acme_model100/presentation.json \
143
+ --descriptor src/benchweave_acme_model100/descriptor.json \
144
+ --resources src/benchweave_acme_model100 \
145
+ --catalogue src/benchweave_acme_model100/binding-catalogue.json \
146
+ --fixtures src/benchweave_acme_model100/ui/fixtures
147
+ ```
148
+
149
+ Use `--no-open` for CI or a terminal-only readiness check. The default listener is an ephemeral port on `127.0.0.1`; wildcard listeners are rejected. A non-loopback host requires `--allow-network` and remains unsuitable for shared or production deployment. UI contributors can point at a compatible Vite renderer with `--renderer-url`; the CLI adds the preview server URL as the renderer's `apiBase` query parameter and permits cross-origin API responses only for that renderer's exact origin. Both renderers require preview API version 1.
150
+
151
+ The command suite uses Click for stable parsing and exit codes and Rich for readable non-interactive output. In an interactive terminal, `preview-ui` uses a Textual status screen: press `o` to reopen the browser and `q` to stop the preview. Textual is deliberately bypassed for `--no-open` and non-terminal output so CI, pipes and SDK tests remain deterministic.
152
+
153
+ Every preview is labelled `SIMULATED PRESENTATION DATA`. Control interactions create only in-memory simulated receipts and never update observed readings optimistically. Preview success is not admission, hardware qualification or permission to operate equipment.
154
+
155
+ ## Public surfaces
156
+
157
+ - `interfaces`: structural async `Adapter`, `HostServices`, `OperationContext` and optional `CaptureServices` definitions. No SDK superclass is required.
158
+ - `testing`: deterministic `MockContext` and `MockHost`, exact scripted transfers, dispatch markers, cancellation and a manually advanced clock. These are test doubles, not qualified host services.
159
+ - `validation`: pinned local schemas, strict finite JSON, format validation, runtime correlation and basic descriptor S01/S02 checks. Unresolved schema references fail without network retrieval.
160
+ - `conformance`: reusable operation and quiet lifecycle checks, with configurable wall-clock timeouts for cooperative async calls. Authors must add device-specific failure, profile and measurement tests. Use process isolation for blocking code or code that suppresses cancellation.
161
+ - `presentation`: bounded offline validation of presentation resources and complete configuration presets, using the same validator bytes as the gateway.
162
+ - `packaging`: inventory and integrity checks for a prepared bundle, including duplicate/path/symlink rejection. No installation, signing, publication or dependency execution.
163
+
164
+ ## Compatibility and limits
165
+
166
+ The gateway has an explicit OTDP bridge and loader for identify, scalar read and scalar write. Profile actions, capture and streaming are not implemented by that bridge. Package-relative and standard-library imports are supported; arbitrary third-party runtime dependencies need further integration. Existing simulator interfaces remain private. Release CI builds an SDK and external plugin outside the checkout and exercises that plugin through the gateway bridge using mock transport. Unsupported operations must fail explicitly. No live install endpoint, physical backend, container device permissions or hardware qualification is supplied by this SDK.
167
+
168
+ The SDK sdist and wheel include the canonical OTDP, registry and plugin presentation contract sets. Build from the repository with `uv build packages/sdk`; the build hook includes contract resources and a wheel rebuilt from the sdist remains self-contained. The release smoke compares installed contract bytes with the canonical repository copies. SDK and gateway versions are independently named; each release must record the exact pair tested before expanding compatibility claims.
169
+
170
+ Pure Python plugins still need declared dependencies and compatible runtimes. Native dependencies and physical transport mappings require a separately qualified gateway deployment. The SDK does not install dependencies into a running gateway.
171
+
172
+ ## Distribution rights
173
+
174
+ The SDK package is distributed under the [MIT licence](LICENSE). The vendored OTDP, registry and presentation contract sets and the generated templates are part of this package and carry the same grant. Plugin authors choose their own licence; generated examples contain no licence grant and make no claim on plugin code written with them.
@@ -0,0 +1,74 @@
1
+ """Verify the vendored standards tree against its lock before packaging."""
2
+
3
+ import hashlib
4
+ import json
5
+ from pathlib import Path
6
+
7
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
8
+
9
+ LOCK_NAME = "standards-lock.json"
10
+ VENDORED = "src/benchweave_sdk/standards"
11
+ STAMP_NAME = "_GENERATED.txt"
12
+
13
+
14
+ def _validate_preview_assets(package: Path) -> None:
15
+ root = package / "preview_assets"
16
+ inventory_path = root / "inventory.json"
17
+ if not inventory_path.is_file():
18
+ raise RuntimeError("Bundled preview inventory missing; run npm run build:preview from ui/")
19
+ try:
20
+ inventory = json.loads(inventory_path.read_bytes())
21
+ assets = inventory["assets"]
22
+ except (json.JSONDecodeError, KeyError, TypeError) as exc:
23
+ raise RuntimeError("Bundled preview inventory is invalid") from exc
24
+ if inventory.get("api_version") != 1 or not isinstance(assets, list) or not assets:
25
+ raise RuntimeError("Bundled preview inventory is incompatible or empty")
26
+ for asset in assets:
27
+ relative = Path(asset["path"])
28
+ if relative.is_absolute() or ".." in relative.parts:
29
+ raise RuntimeError(f"Unsafe preview asset path: {relative}")
30
+ content = (root / relative).read_bytes()
31
+ if len(content) != asset["size"] or hashlib.sha256(content).hexdigest() != asset["sha256"]:
32
+ raise RuntimeError(f"Bundled preview asset is stale or corrupt: {relative}")
33
+
34
+
35
+ def _verify_vendored_file(tree: Path, relative: str, digest: str) -> None:
36
+ path = Path(relative)
37
+ if path.is_absolute() or ".." in path.parts:
38
+ raise RuntimeError(f"Unsafe vendored standards path: {relative}")
39
+ target = tree / path
40
+ if not target.is_file():
41
+ raise RuntimeError(f"Vendored standards file missing: {relative}")
42
+ if hashlib.sha256(target.read_bytes()).hexdigest() != digest:
43
+ raise RuntimeError(f"Vendored standards file is stale or corrupt: {relative}")
44
+
45
+
46
+ def _validate_vendored_standards(root: Path) -> None:
47
+ tree = root / VENDORED
48
+ lock_path = root / LOCK_NAME
49
+ if not tree.is_dir() or not lock_path.is_file():
50
+ raise RuntimeError(
51
+ "Vendored standards tree or lock missing; "
52
+ "run benchweave-sdk sync-standards <bundle> from packages/sdk"
53
+ )
54
+ try:
55
+ lock = json.loads(lock_path.read_bytes())
56
+ standards = lock["standards"]
57
+ if lock.get("lock_version") != 1 or not isinstance(standards, list) or not standards:
58
+ raise RuntimeError("Bundled standards lock is incompatible or empty")
59
+ for standard in standards:
60
+ identifier = standard["id"]
61
+ if not (tree / identifier / STAMP_NAME).is_file():
62
+ raise RuntimeError(f"Vendored standard stamp missing: {identifier}/{STAMP_NAME}")
63
+ for file in standard["files"]:
64
+ _verify_vendored_file(tree, file["path"], file["sha256"])
65
+ except (json.JSONDecodeError, KeyError, TypeError) as exc:
66
+ raise RuntimeError("Bundled standards lock is invalid") from exc
67
+
68
+
69
+ class CustomBuildHook(BuildHookInterface):
70
+ def initialize(self, version, build_data):
71
+ root = Path(self.root)
72
+ package = root / "src/benchweave_sdk"
73
+ _validate_preview_assets(package)
74
+ _validate_vendored_standards(root)
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.26"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "benchweave-sdk"
7
+ version = "0.0.1"
8
+ description = "Offline authoring and conformance tools for BenchWeave OTDP device plugins."
9
+ readme = "README.md"
10
+ requires-python = ">=3.13"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ dependencies = [
14
+ "click>=8.3,<9",
15
+ "jsonschema>=4.23",
16
+ "referencing>=0.35",
17
+ "rfc3339-validator>=0.1.4",
18
+ "rfc3987>=1.3.8",
19
+ "rich>=14,<15",
20
+ "textual>=8.2,<9",
21
+ ]
22
+
23
+ [project.optional-dependencies]
24
+ test = ["pytest>=8.0"]
25
+
26
+ [project.scripts]
27
+ benchweave-sdk = "benchweave_sdk.cli:main"
28
+
29
+ [tool.hatch.build.targets.wheel]
30
+ packages = ["src/benchweave_sdk"]
31
+
32
+ [tool.hatch.build.targets.sdist]
33
+ include = ["src", "pyproject.toml", "README.md", "hatch_build.py", "standards-lock.json"]
34
+
35
+ [tool.hatch.build.hooks.custom]
36
+
37
+ [dependency-groups]
38
+ dev = [
39
+ "mypy>=1.11",
40
+ "ruff>=0.6",
41
+ "types-jsonschema>=4.26.0.20260518",
42
+ ]
43
+
44
+ [tool.ruff]
45
+ line-length = 100
46
+ target-version = "py313"
47
+ extend-exclude = ["docs"]
48
+
49
+ [tool.ruff.lint]
50
+ select = ["E", "F", "I", "UP", "B", "SIM"]
51
+
52
+ [tool.mypy]
53
+ python_version = "3.13"
54
+ strict = true
55
+ files = ["src"]
@@ -0,0 +1,8 @@
1
+ """Public authoring surface for OTDP 0.3.0 / adapter API 1.1."""
2
+
3
+ from .interfaces import Adapter, HostServices, OperationContext
4
+
5
+ __version__ = "0.1.0"
6
+ OTDP_VERSION = "0.3.0"
7
+ ADAPTER_API_VERSION = "1.1"
8
+ __all__ = ["Adapter", "HostServices", "OperationContext"]