softschema 0.1.2__tar.gz → 0.1.3__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.
- {softschema-0.1.2 → softschema-0.1.3}/.gitignore +6 -0
- {softschema-0.1.2 → softschema-0.1.3}/AGENTS.md +12 -2
- {softschema-0.1.2 → softschema-0.1.3}/PKG-INFO +87 -20
- {softschema-0.1.2 → softschema-0.1.3}/README.md +84 -18
- {softschema-0.1.2 → softschema-0.1.3}/docs/development.md +73 -2
- softschema-0.1.3/docs/publishing-npm.md +210 -0
- softschema-0.1.3/docs/publishing.md +188 -0
- {softschema-0.1.2 → softschema-0.1.3}/docs/softschema-guide.md +21 -17
- {softschema-0.1.2 → softschema-0.1.3}/docs/softschema-python-design.md +50 -5
- {softschema-0.1.2 → softschema-0.1.3}/docs/softschema-spec.md +4 -1
- softschema-0.1.3/docs/softschema-typescript-design.md +101 -0
- {softschema-0.1.2 → softschema-0.1.3}/examples/movie_page/README.md +2 -2
- {softschema-0.1.2 → softschema-0.1.3}/examples/movie_page/movie-page.schema.yaml +46 -74
- {softschema-0.1.2 → softschema-0.1.3}/examples/movie_page/spirited-away.md +1 -1
- softschema-0.1.3/examples/parity/__init__.py +0 -0
- softschema-0.1.3/examples/parity/model.py +94 -0
- softschema-0.1.3/examples/parity/parity.schema.yaml +147 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/__init__.py +0 -6
- softschema-0.1.3/packages/python/src/softschema/canonicalize.py +133 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/cli.py +8 -1
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/compile.py +32 -24
- softschema-0.1.3/packages/python/src/softschema/errors.py +102 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/generate.py +7 -5
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/models.py +0 -20
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/schema_view.py +16 -14
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/validate.py +79 -198
- softschema-0.1.3/packages/python/tests/test_canonicalize.py +53 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/tests/test_cli.py +5 -4
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/tests/test_core.py +29 -78
- softschema-0.1.3/packages/python/tests/test_errors.py +51 -0
- softschema-0.1.3/packages/python/tests/test_parity.py +30 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/tests/test_schema_view.py +31 -2
- softschema-0.1.3/packages/python/tests/test_skill_mirror_drift.py +32 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/tests/test_soft_field.py +2 -2
- softschema-0.1.3/packages/typescript/LICENSE +21 -0
- softschema-0.1.3/packages/typescript/README.md +54 -0
- {softschema-0.1.2 → softschema-0.1.3}/pyproject.toml +12 -2
- {softschema-0.1.2 → softschema-0.1.3}/skills/softschema/SKILL.md +17 -7
- softschema-0.1.3/tests/golden/README.md +68 -0
- softschema-0.1.2/docs/publishing.md +0 -91
- softschema-0.1.2/packages/typescript/README.md +0 -26
- {softschema-0.1.2 → softschema-0.1.3}/LICENSE +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/docs/installation.md +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/examples/__init__.py +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/examples/movie_page/__init__.py +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/examples/movie_page/host_integration.py +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/examples/movie_page/model.py +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/README.md +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/py.typed +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/registry.py +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/src/softschema/soft_field.py +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/tests/test_generate.py +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/tests/test_movie_page_example.py +0 -0
- {softschema-0.1.2 → softschema-0.1.3}/packages/python/tests/test_warning_codes.py +0 -0
|
@@ -6,6 +6,9 @@ __pycache__/
|
|
|
6
6
|
# C extensions
|
|
7
7
|
*.so
|
|
8
8
|
|
|
9
|
+
# Node / TypeScript
|
|
10
|
+
node_modules/
|
|
11
|
+
|
|
9
12
|
# Distribution / packaging
|
|
10
13
|
.Python
|
|
11
14
|
build/
|
|
@@ -223,3 +226,6 @@ __marimo__/
|
|
|
223
226
|
|
|
224
227
|
# Streamlit
|
|
225
228
|
.streamlit/secrets.toml
|
|
229
|
+
|
|
230
|
+
# TS bundled doc/skill resources (generated at build by copy-resources)
|
|
231
|
+
packages/typescript/resources/
|
|
@@ -9,11 +9,21 @@ Start here:
|
|
|
9
9
|
- [Softschema Spec](docs/softschema-spec.md): exact language-neutral artifact format.
|
|
10
10
|
- [Movie page example](examples/movie_page/README.md): complete Python-backed example.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
softschema ships two interchangeable implementations with the same CLI and library
|
|
13
|
+
surface: Python/Pydantic (`softschema`, `softschema-py`) and TypeScript/Zod
|
|
14
|
+
(`softschema`, `softschema-ts`). They are held to exact behavioral parity: same flags,
|
|
15
|
+
same canonical JSON Schema sidecar, same validation results, so authoring an artifact is
|
|
16
|
+
identical regardless of which you run.
|
|
17
|
+
|
|
18
|
+
For implementer reference (only when changing a package itself):
|
|
13
19
|
|
|
14
20
|
- [Python Package Design](docs/softschema-python-design.md): module layout, CLI surface,
|
|
15
21
|
validation layers, and ADR-style decisions.
|
|
16
|
-
|
|
22
|
+
- [TypeScript Package Design](docs/softschema-typescript-design.md): the Zod port and
|
|
23
|
+
the Python↔TypeScript API parity table.
|
|
24
|
+
- When changing behavior, follow the parity development process (golden-first, then port
|
|
25
|
+
to both) in [docs/development.md](docs/development.md).
|
|
26
|
+
Skip all of this when only authoring or validating artifacts.
|
|
17
27
|
|
|
18
28
|
Key rules:
|
|
19
29
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: softschema
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Soft schema conventions and validation tools for Markdown/YAML artifacts
|
|
5
5
|
Project-URL: Homepage, https://github.com/jlevy/softschema
|
|
6
6
|
Project-URL: Repository, https://github.com/jlevy/softschema
|
|
@@ -22,7 +22,8 @@ Requires-Python: <4.0,>=3.11
|
|
|
22
22
|
Requires-Dist: frontmatter-format>=0.3.0
|
|
23
23
|
Requires-Dist: jsonschema>=4.20
|
|
24
24
|
Requires-Dist: pydantic>=2
|
|
25
|
-
Requires-Dist:
|
|
25
|
+
Requires-Dist: ruamel-yaml>=0.18
|
|
26
|
+
Requires-Dist: strif>=3.1.0
|
|
26
27
|
Description-Content-Type: text/markdown
|
|
27
28
|
|
|
28
29
|
# softschema
|
|
@@ -131,14 +132,41 @@ This repo is simply:
|
|
|
131
132
|
defining soft schema file format conventions for Markdown documents with YAML
|
|
132
133
|
frontmatter.
|
|
133
134
|
|
|
134
|
-
- A
|
|
135
|
-
|
|
135
|
+
- A small CLI (and library) that handles formatting, compilation, validation, and other
|
|
136
|
+
common workflows on soft schema-style documents.
|
|
136
137
|
|
|
137
138
|
The CLI can be used directly, as a library, or installed as a skill.
|
|
138
139
|
|
|
139
140
|
For the full conceptual reference and adoption playbooks, see the
|
|
140
141
|
[Softschema Guide](docs/softschema-guide.md).
|
|
141
142
|
|
|
143
|
+
## Two Synchronized Implementations
|
|
144
|
+
|
|
145
|
+
softschema ships **two complete, fully supported implementations** with the same CLI and
|
|
146
|
+
library surface:
|
|
147
|
+
|
|
148
|
+
- **Python / Pydantic**: [`softschema`](docs/softschema-python-design.md) on PyPI (run
|
|
149
|
+
as `softschema` or `softschema-py`).
|
|
150
|
+
- **TypeScript / Zod**: [`softschema`](docs/softschema-typescript-design.md) on npm (run
|
|
151
|
+
as `softschema` or `softschema-ts`).
|
|
152
|
+
|
|
153
|
+
The TypeScript package is a **synchronized port** of the Python one, held to **exact
|
|
154
|
+
behavioral parity**: equivalent CLI inputs, outputs, and flags; equivalent library APIs;
|
|
155
|
+
the same canonical JSON Schema sidecar (byte-identical, with an equal `schema_sha256`
|
|
156
|
+
fingerprint); and the same engine-neutral validation results.
|
|
157
|
+
Only idiomatic surface details differ (snake_case ↔ camelCase, Pydantic ↔ Zod).
|
|
158
|
+
Authoring or validating an artifact is identical regardless of which you run, so a team
|
|
159
|
+
can adopt either runtime, or both, without divergence.
|
|
160
|
+
|
|
161
|
+
The two are **maintained in lockstep**: every behavior change lands in a shared
|
|
162
|
+
golden-test corpus first, then in both packages, and CI fails if their outputs or
|
|
163
|
+
compiled schemas drift.
|
|
164
|
+
They release together under **the same version number** on PyPI and npm.
|
|
165
|
+
See
|
|
166
|
+
[Keeping Python and TypeScript in Parity](docs/development.md#keeping-python-and-typescript-in-parity)
|
|
167
|
+
for the development process and the parity invariants CI enforces, and
|
|
168
|
+
[Publishing](docs/publishing.md) for the synchronized release.
|
|
169
|
+
|
|
142
170
|
## Example Artifact Shape
|
|
143
171
|
|
|
144
172
|
The default shape is Markdown with YAML frontmatter.
|
|
@@ -216,7 +244,7 @@ from the audience; IMDb users give it 8.6 out of 10 across more than 850,000 vot
|
|
|
216
244
|
| Source | Score | Count |
|
|
217
245
|
| --- | ---: | ---: |
|
|
218
246
|
| Rotten Tomatoes Critics | 96% Tomatometer | 225 reviews |
|
|
219
|
-
| Rotten Tomatoes Audience | 96% Popcornmeter |
|
|
247
|
+
| Rotten Tomatoes Audience | 96% Popcornmeter | n/a |
|
|
220
248
|
| IMDb | 8.6 / 10 | 850,000+ votes |
|
|
221
249
|
```
|
|
222
250
|
|
|
@@ -304,52 +332,91 @@ uv run softschema compile examples.movie_page.model:MoviePage \
|
|
|
304
332
|
--out examples/movie_page/movie-page.schema.yaml
|
|
305
333
|
```
|
|
306
334
|
|
|
335
|
+
## Try the TypeScript Package
|
|
336
|
+
|
|
337
|
+
The TypeScript CLI takes the same arguments and emits byte-identical output.
|
|
338
|
+
Validate the same artifact against the same language-neutral schema sidecar with a
|
|
339
|
+
pinned zero-install runner:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
npx softschema@latest validate examples/movie_page/spirited-away.md \
|
|
343
|
+
--schema examples/movie_page/movie-page.schema.yaml \
|
|
344
|
+
--envelope movie
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
The bundled docs and skill are served identically:
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
npx softschema@latest docs --list
|
|
351
|
+
npx softschema@latest docs guide
|
|
352
|
+
npx softschema@latest skill --brief
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Semantic models are written in Zod instead of Pydantic; everything else (flags, result
|
|
356
|
+
JSON, error records, and the compiled sidecar, down to its `schema_sha256`) matches the
|
|
357
|
+
Python package exactly.
|
|
358
|
+
See the [TypeScript Design](docs/softschema-typescript-design.md) doc for the Zod model
|
|
359
|
+
shape and the full Python ↔ TypeScript API table.
|
|
360
|
+
|
|
307
361
|
## Use as an Agent Skill
|
|
308
362
|
|
|
309
|
-
|
|
363
|
+
Both packages ship the same [`SKILL.md`](https://agentskills.io) following the open
|
|
310
364
|
Agent Skills standard discovered by Claude Code, Codex, Gemini CLI, Cursor, Copilot, and
|
|
311
365
|
~20 other coding agents.
|
|
312
366
|
Pointing an agent at the CLI is enough to bootstrap its understanding of the soft-schema
|
|
313
367
|
approach: the `--help` epilog routes it to a brief and the bundled docs.
|
|
314
368
|
|
|
315
369
|
```bash
|
|
316
|
-
|
|
317
|
-
uvx softschema@
|
|
318
|
-
uvx softschema@
|
|
370
|
+
# Python:
|
|
371
|
+
uvx softschema@latest --help # entry point with bootstrap pointers
|
|
372
|
+
uvx softschema@latest skill --brief # compact operating brief
|
|
373
|
+
uvx softschema@latest docs guide # full mental model and adoption path
|
|
374
|
+
|
|
375
|
+
# TypeScript (same commands, same bundled docs/skill):
|
|
376
|
+
npx softschema@latest skill --brief
|
|
377
|
+
npx softschema@latest docs guide
|
|
319
378
|
```
|
|
320
379
|
|
|
321
|
-
Self-install the skill into a project so any agent working in the repo finds it
|
|
322
|
-
|
|
380
|
+
Self-install the skill into a project so any agent working in the repo finds it natively
|
|
381
|
+
(either package writes the identical mirrors):
|
|
323
382
|
|
|
324
383
|
```bash
|
|
325
|
-
uvx softschema@
|
|
384
|
+
uvx softschema@latest skill --install
|
|
385
|
+
# or: npx softschema@latest skill --install
|
|
326
386
|
# writes:
|
|
327
387
|
# .agents/skills/softschema/SKILL.md (Codex, Gemini CLI, cross-agent installers)
|
|
328
388
|
# .claude/skills/softschema/SKILL.md (Claude Code mirror)
|
|
329
389
|
```
|
|
330
390
|
|
|
331
|
-
Both mirrors carry a `DO NOT EDIT` marker
|
|
332
|
-
Re-run `
|
|
391
|
+
Both mirrors carry a `DO NOT EDIT` marker.
|
|
392
|
+
Re-run `skill --install` to refresh after upgrading the CLI.
|
|
333
393
|
|
|
334
394
|
## Repository Layout
|
|
335
395
|
|
|
336
396
|
```text
|
|
337
|
-
docs/ guide, spec, Python
|
|
397
|
+
docs/ guide, spec, package design (Python + TypeScript), and workflow docs
|
|
338
398
|
examples/movie_page/ complete example with model, host integration, artifact, schema
|
|
339
|
-
|
|
340
|
-
packages/
|
|
341
|
-
|
|
399
|
+
examples/parity/ cross-language parity fixture (Pydantic + Zod compile to one schema)
|
|
400
|
+
packages/python/ Python/Pydantic implementation and tests
|
|
401
|
+
packages/typescript/ TypeScript/Zod implementation and tests
|
|
402
|
+
skills/softschema/ agent-facing usage guidance (shared SKILL.md source)
|
|
403
|
+
tests/golden/ shared CLI golden corpus, run against both implementations
|
|
342
404
|
```
|
|
343
405
|
|
|
344
406
|
The root `pyproject.toml` builds the Python package from
|
|
345
|
-
`packages/python/src/softschema
|
|
346
|
-
|
|
407
|
+
`packages/python/src/softschema`; `packages/typescript` builds the npm `softschema`
|
|
408
|
+
package with bun. The shared golden corpus and the cross-language conformance test keep
|
|
409
|
+
the two implementations byte-for-byte in sync.
|
|
347
410
|
|
|
348
411
|
## Development and Contributing
|
|
349
412
|
|
|
350
413
|
See [Development](docs/development.md) for repo setup, common commands, CI checks,
|
|
351
414
|
release workflow, and pointers to the installation and publishing docs.
|
|
352
415
|
|
|
416
|
+
The Python and TypeScript implementations **must be kept in exact sync**. Any behavior
|
|
417
|
+
change goes through the shared golden corpus first and then lands in both packages; see
|
|
418
|
+
[Keeping Python and TypeScript in Parity](docs/development.md#keeping-python-and-typescript-in-parity).
|
|
419
|
+
|
|
353
420
|
<!-- This document follows common-doc-guidelines.md.
|
|
354
421
|
See github.com/jlevy/practical-prose and review guidelines before editing.
|
|
355
422
|
-->
|
|
@@ -104,14 +104,41 @@ This repo is simply:
|
|
|
104
104
|
defining soft schema file format conventions for Markdown documents with YAML
|
|
105
105
|
frontmatter.
|
|
106
106
|
|
|
107
|
-
- A
|
|
108
|
-
|
|
107
|
+
- A small CLI (and library) that handles formatting, compilation, validation, and other
|
|
108
|
+
common workflows on soft schema-style documents.
|
|
109
109
|
|
|
110
110
|
The CLI can be used directly, as a library, or installed as a skill.
|
|
111
111
|
|
|
112
112
|
For the full conceptual reference and adoption playbooks, see the
|
|
113
113
|
[Softschema Guide](docs/softschema-guide.md).
|
|
114
114
|
|
|
115
|
+
## Two Synchronized Implementations
|
|
116
|
+
|
|
117
|
+
softschema ships **two complete, fully supported implementations** with the same CLI and
|
|
118
|
+
library surface:
|
|
119
|
+
|
|
120
|
+
- **Python / Pydantic**: [`softschema`](docs/softschema-python-design.md) on PyPI (run
|
|
121
|
+
as `softschema` or `softschema-py`).
|
|
122
|
+
- **TypeScript / Zod**: [`softschema`](docs/softschema-typescript-design.md) on npm (run
|
|
123
|
+
as `softschema` or `softschema-ts`).
|
|
124
|
+
|
|
125
|
+
The TypeScript package is a **synchronized port** of the Python one, held to **exact
|
|
126
|
+
behavioral parity**: equivalent CLI inputs, outputs, and flags; equivalent library APIs;
|
|
127
|
+
the same canonical JSON Schema sidecar (byte-identical, with an equal `schema_sha256`
|
|
128
|
+
fingerprint); and the same engine-neutral validation results.
|
|
129
|
+
Only idiomatic surface details differ (snake_case ↔ camelCase, Pydantic ↔ Zod).
|
|
130
|
+
Authoring or validating an artifact is identical regardless of which you run, so a team
|
|
131
|
+
can adopt either runtime, or both, without divergence.
|
|
132
|
+
|
|
133
|
+
The two are **maintained in lockstep**: every behavior change lands in a shared
|
|
134
|
+
golden-test corpus first, then in both packages, and CI fails if their outputs or
|
|
135
|
+
compiled schemas drift.
|
|
136
|
+
They release together under **the same version number** on PyPI and npm.
|
|
137
|
+
See
|
|
138
|
+
[Keeping Python and TypeScript in Parity](docs/development.md#keeping-python-and-typescript-in-parity)
|
|
139
|
+
for the development process and the parity invariants CI enforces, and
|
|
140
|
+
[Publishing](docs/publishing.md) for the synchronized release.
|
|
141
|
+
|
|
115
142
|
## Example Artifact Shape
|
|
116
143
|
|
|
117
144
|
The default shape is Markdown with YAML frontmatter.
|
|
@@ -189,7 +216,7 @@ from the audience; IMDb users give it 8.6 out of 10 across more than 850,000 vot
|
|
|
189
216
|
| Source | Score | Count |
|
|
190
217
|
| --- | ---: | ---: |
|
|
191
218
|
| Rotten Tomatoes Critics | 96% Tomatometer | 225 reviews |
|
|
192
|
-
| Rotten Tomatoes Audience | 96% Popcornmeter |
|
|
219
|
+
| Rotten Tomatoes Audience | 96% Popcornmeter | n/a |
|
|
193
220
|
| IMDb | 8.6 / 10 | 850,000+ votes |
|
|
194
221
|
```
|
|
195
222
|
|
|
@@ -277,52 +304,91 @@ uv run softschema compile examples.movie_page.model:MoviePage \
|
|
|
277
304
|
--out examples/movie_page/movie-page.schema.yaml
|
|
278
305
|
```
|
|
279
306
|
|
|
307
|
+
## Try the TypeScript Package
|
|
308
|
+
|
|
309
|
+
The TypeScript CLI takes the same arguments and emits byte-identical output.
|
|
310
|
+
Validate the same artifact against the same language-neutral schema sidecar with a
|
|
311
|
+
pinned zero-install runner:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
npx softschema@latest validate examples/movie_page/spirited-away.md \
|
|
315
|
+
--schema examples/movie_page/movie-page.schema.yaml \
|
|
316
|
+
--envelope movie
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
The bundled docs and skill are served identically:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
npx softschema@latest docs --list
|
|
323
|
+
npx softschema@latest docs guide
|
|
324
|
+
npx softschema@latest skill --brief
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Semantic models are written in Zod instead of Pydantic; everything else (flags, result
|
|
328
|
+
JSON, error records, and the compiled sidecar, down to its `schema_sha256`) matches the
|
|
329
|
+
Python package exactly.
|
|
330
|
+
See the [TypeScript Design](docs/softschema-typescript-design.md) doc for the Zod model
|
|
331
|
+
shape and the full Python ↔ TypeScript API table.
|
|
332
|
+
|
|
280
333
|
## Use as an Agent Skill
|
|
281
334
|
|
|
282
|
-
|
|
335
|
+
Both packages ship the same [`SKILL.md`](https://agentskills.io) following the open
|
|
283
336
|
Agent Skills standard discovered by Claude Code, Codex, Gemini CLI, Cursor, Copilot, and
|
|
284
337
|
~20 other coding agents.
|
|
285
338
|
Pointing an agent at the CLI is enough to bootstrap its understanding of the soft-schema
|
|
286
339
|
approach: the `--help` epilog routes it to a brief and the bundled docs.
|
|
287
340
|
|
|
288
341
|
```bash
|
|
289
|
-
|
|
290
|
-
uvx softschema@
|
|
291
|
-
uvx softschema@
|
|
342
|
+
# Python:
|
|
343
|
+
uvx softschema@latest --help # entry point with bootstrap pointers
|
|
344
|
+
uvx softschema@latest skill --brief # compact operating brief
|
|
345
|
+
uvx softschema@latest docs guide # full mental model and adoption path
|
|
346
|
+
|
|
347
|
+
# TypeScript (same commands, same bundled docs/skill):
|
|
348
|
+
npx softschema@latest skill --brief
|
|
349
|
+
npx softschema@latest docs guide
|
|
292
350
|
```
|
|
293
351
|
|
|
294
|
-
Self-install the skill into a project so any agent working in the repo finds it
|
|
295
|
-
|
|
352
|
+
Self-install the skill into a project so any agent working in the repo finds it natively
|
|
353
|
+
(either package writes the identical mirrors):
|
|
296
354
|
|
|
297
355
|
```bash
|
|
298
|
-
uvx softschema@
|
|
356
|
+
uvx softschema@latest skill --install
|
|
357
|
+
# or: npx softschema@latest skill --install
|
|
299
358
|
# writes:
|
|
300
359
|
# .agents/skills/softschema/SKILL.md (Codex, Gemini CLI, cross-agent installers)
|
|
301
360
|
# .claude/skills/softschema/SKILL.md (Claude Code mirror)
|
|
302
361
|
```
|
|
303
362
|
|
|
304
|
-
Both mirrors carry a `DO NOT EDIT` marker
|
|
305
|
-
Re-run `
|
|
363
|
+
Both mirrors carry a `DO NOT EDIT` marker.
|
|
364
|
+
Re-run `skill --install` to refresh after upgrading the CLI.
|
|
306
365
|
|
|
307
366
|
## Repository Layout
|
|
308
367
|
|
|
309
368
|
```text
|
|
310
|
-
docs/ guide, spec, Python
|
|
369
|
+
docs/ guide, spec, package design (Python + TypeScript), and workflow docs
|
|
311
370
|
examples/movie_page/ complete example with model, host integration, artifact, schema
|
|
312
|
-
|
|
313
|
-
packages/
|
|
314
|
-
|
|
371
|
+
examples/parity/ cross-language parity fixture (Pydantic + Zod compile to one schema)
|
|
372
|
+
packages/python/ Python/Pydantic implementation and tests
|
|
373
|
+
packages/typescript/ TypeScript/Zod implementation and tests
|
|
374
|
+
skills/softschema/ agent-facing usage guidance (shared SKILL.md source)
|
|
375
|
+
tests/golden/ shared CLI golden corpus, run against both implementations
|
|
315
376
|
```
|
|
316
377
|
|
|
317
378
|
The root `pyproject.toml` builds the Python package from
|
|
318
|
-
`packages/python/src/softschema
|
|
319
|
-
|
|
379
|
+
`packages/python/src/softschema`; `packages/typescript` builds the npm `softschema`
|
|
380
|
+
package with bun. The shared golden corpus and the cross-language conformance test keep
|
|
381
|
+
the two implementations byte-for-byte in sync.
|
|
320
382
|
|
|
321
383
|
## Development and Contributing
|
|
322
384
|
|
|
323
385
|
See [Development](docs/development.md) for repo setup, common commands, CI checks,
|
|
324
386
|
release workflow, and pointers to the installation and publishing docs.
|
|
325
387
|
|
|
388
|
+
The Python and TypeScript implementations **must be kept in exact sync**. Any behavior
|
|
389
|
+
change goes through the shared golden corpus first and then lands in both packages; see
|
|
390
|
+
[Keeping Python and TypeScript in Parity](docs/development.md#keeping-python-and-typescript-in-parity).
|
|
391
|
+
|
|
326
392
|
<!-- This document follows common-doc-guidelines.md.
|
|
327
393
|
See github.com/jlevy/practical-prose and review guidelines before editing.
|
|
328
394
|
-->
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
First-time setup of `uv` and Python is covered in [Installation](installation.md).
|
|
4
4
|
Release workflow and PyPI steps are covered in [Publishing](publishing.md).
|
|
5
5
|
|
|
6
|
-
Set up the repo:
|
|
6
|
+
Set up the repo (Python deps, Node tooling for hooks, and the git hooks themselves):
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
uv sync --all-extras
|
|
9
|
+
make install # uv sync --all-extras + npm install (lefthook)
|
|
10
|
+
make hooks-install # install the lefthook pre-commit hooks
|
|
10
11
|
```
|
|
11
12
|
|
|
13
|
+
`make install` alone (or `uv sync --all-extras`) is enough to run tests and builds;
|
|
14
|
+
`make hooks-install` additionally wires up the pre-commit hooks described below.
|
|
15
|
+
|
|
12
16
|
Common workflows:
|
|
13
17
|
|
|
14
18
|
```bash
|
|
@@ -31,6 +35,37 @@ uv build
|
|
|
31
35
|
|
|
32
36
|
The Python package is built from `packages/python/src/softschema`.
|
|
33
37
|
|
|
38
|
+
### Git hooks (this repo)
|
|
39
|
+
|
|
40
|
+
Hooks are managed by [lefthook](https://lefthook.dev) (`lefthook.yml`), installed with
|
|
41
|
+
`make hooks-install`. The `pre-commit` hook formats staged changes so commits stay
|
|
42
|
+
clean:
|
|
43
|
+
|
|
44
|
+
- **Markdown:** delegates to `make format` (pinned `flowmark-rs` and
|
|
45
|
+
`softschema generate`); the single source of truth, the same command you run locally.
|
|
46
|
+
- **Python:** `ruff format` and `ruff check --fix` on staged `*.py`.
|
|
47
|
+
- **TypeScript:** `biome check --write` on staged files in `packages/typescript`.
|
|
48
|
+
|
|
49
|
+
Bypass for an emergency commit with `git commit --no-verify` (avoid in PRs).
|
|
50
|
+
flowmark runs across the whole tree (it honors `.flowmarkignore` only relative to its
|
|
51
|
+
target arg), so staging any `*.md` reformats all Markdown; this is fast and idempotent.
|
|
52
|
+
|
|
53
|
+
## TypeScript Package
|
|
54
|
+
|
|
55
|
+
The TypeScript/Zod package lives in `packages/typescript` and builds with bun (bunup and
|
|
56
|
+
biome). Set it up and run its checks:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cd packages/typescript
|
|
60
|
+
bun install --frozen-lockfile
|
|
61
|
+
bun run check # biome lint, tsc --noEmit, bun test (+ coverage gate)
|
|
62
|
+
bun run build # copy-resources + bunup → dist/
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
It publishes to npm as `softschema` (the same name as the PyPI package) and exposes the
|
|
66
|
+
CLI as both `softschema` and `softschema-ts`. The two packages **release together under
|
|
67
|
+
one version number**; see [Publishing](publishing.md).
|
|
68
|
+
|
|
34
69
|
Documentation changes should follow `common-doc-guidelines.md`
|
|
35
70
|
(github.com/jlevy/practical-prose).
|
|
36
71
|
Keep the README short, keep conceptual guidance in `docs/softschema-guide.md`, and keep
|
|
@@ -132,6 +167,42 @@ repos:
|
|
|
132
167
|
Adapt the paths and the `--model` / `--contract` / `--out` arguments to each schema in
|
|
133
168
|
your repository.
|
|
134
169
|
|
|
170
|
+
## Keeping Python and TypeScript in Parity
|
|
171
|
+
|
|
172
|
+
softschema ships two implementations, Python/Pydantic (`softschema`) and TypeScript/Zod
|
|
173
|
+
(`softschema`, `softschema-ts`), held to **exact behavioral parity**: equivalent CLI
|
|
174
|
+
inputs/outputs/flags and library APIs, the same canonical JSON Schema sidecar
|
|
175
|
+
(byte-identical, equal `schema_sha256`), and the same engine-neutral validation results.
|
|
176
|
+
Only idiomatic surface differs (snake_case ↔ camelCase, Pydantic ↔ Zod).
|
|
177
|
+
|
|
178
|
+
When you change any behavior, follow this loop so the two never drift:
|
|
179
|
+
|
|
180
|
+
1. **Golden first.** Write or update the shared scenario in `tests/golden/scenarios/`
|
|
181
|
+
(neutral, runs on both) or `tests/golden/scenarios-{py,ts}/` (per-language
|
|
182
|
+
invocation, identical output) **before** touching code.
|
|
183
|
+
2. **Implement in Python**, then `uv run pytest` and
|
|
184
|
+
`SOFTSCHEMA_IMPL=py bash tests/golden/run.sh`.
|
|
185
|
+
3. **Port to TypeScript**, then `bun test` (in `packages/typescript`) and
|
|
186
|
+
`SOFTSCHEMA_IMPL=ts bash tests/golden/run.sh`.
|
|
187
|
+
4. **Both green and conformance.** Both golden runs and the cross-implementation
|
|
188
|
+
conformance test (the Zod and Pydantic compilers produce an identical canonical
|
|
189
|
+
sidecar) pass in CI.
|
|
190
|
+
|
|
191
|
+
The parity invariants, and where each is enforced:
|
|
192
|
+
|
|
193
|
+
| Invariant | Enforced by |
|
|
194
|
+
| --- | --- |
|
|
195
|
+
| Canonical schema (equal `schema_sha256`) | `compile` and the KitchenSink conformance test (`packages/typescript/test/conformance.test.ts`) and `examples/parity/` |
|
|
196
|
+
| Engine-neutral structural errors | shared message templates (`errors`), the golden corpus |
|
|
197
|
+
| Byte-identical neutral CLI output | the shared golden corpus (run twice via `SOFTSCHEMA_IMPL`) |
|
|
198
|
+
| Equal flag/command surface | per-impl and neutral golden scenarios |
|
|
199
|
+
| Bundled docs/skill resolve from the package | the standalone test (`packages/typescript/test/standalone.test.ts`) |
|
|
200
|
+
| Skill mirrors never go stale | the mirror drift test (`tests/test_skill_mirror_drift.py`) |
|
|
201
|
+
|
|
202
|
+
Semantic invariants that JSON Schema cannot express (Pydantic validators ↔ Zod
|
|
203
|
+
refinements) are implementation-specific by design and tested per-language, not in the
|
|
204
|
+
shared corpus.
|
|
205
|
+
|
|
135
206
|
<!-- This document follows common-doc-guidelines.md.
|
|
136
207
|
See github.com/jlevy/practical-prose and review guidelines before editing.
|
|
137
208
|
-->
|