softschema 0.1.4__tar.gz → 0.2.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 (58) hide show
  1. {softschema-0.1.4 → softschema-0.2.1}/AGENTS.md +5 -5
  2. {softschema-0.1.4 → softschema-0.2.1}/PKG-INFO +117 -177
  3. {softschema-0.1.4 → softschema-0.2.1}/README.md +116 -176
  4. {softschema-0.1.4 → softschema-0.2.1}/docs/development.md +19 -18
  5. softschema-0.2.1/docs/e2e-testing.runbook.md +227 -0
  6. softschema-0.2.1/docs/installation.md +89 -0
  7. {softschema-0.1.4 → softschema-0.2.1}/docs/publishing.md +54 -38
  8. {softschema-0.1.4 → softschema-0.2.1}/docs/softschema-guide.md +126 -64
  9. {softschema-0.1.4 → softschema-0.2.1}/docs/softschema-python-design.md +64 -38
  10. softschema-0.2.1/docs/softschema-spec.md +437 -0
  11. {softschema-0.1.4 → softschema-0.2.1}/docs/softschema-typescript-design.md +32 -10
  12. {softschema-0.1.4 → softschema-0.2.1}/examples/movie_page/README.md +22 -17
  13. {softschema-0.1.4 → softschema-0.2.1}/examples/movie_page/spirited-away.md +2 -0
  14. {softschema-0.1.4 → softschema-0.2.1}/packages/python/README.md +3 -3
  15. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/canonicalize.py +3 -3
  16. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/cli.py +53 -14
  17. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/compile.py +5 -5
  18. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/errors.py +2 -2
  19. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/generate.py +30 -18
  20. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/models.py +39 -2
  21. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/schema_view.py +4 -4
  22. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/soft_field.py +4 -4
  23. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/validate.py +69 -18
  24. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_cli.py +5 -20
  25. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_core.py +41 -3
  26. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_generate.py +40 -12
  27. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_movie_page_example.py +26 -18
  28. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_parity.py +3 -3
  29. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_schema_view.py +1 -1
  30. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_soft_field.py +7 -12
  31. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_warning_codes.py +0 -5
  32. {softschema-0.1.4 → softschema-0.2.1}/packages/typescript/README.md +5 -5
  33. {softschema-0.1.4 → softschema-0.2.1}/skills/softschema/SKILL.md +10 -6
  34. {softschema-0.1.4 → softschema-0.2.1}/tests/golden/README.md +3 -3
  35. softschema-0.1.4/docs/installation.md +0 -74
  36. softschema-0.1.4/docs/softschema-spec.md +0 -260
  37. {softschema-0.1.4 → softschema-0.2.1}/.gitignore +0 -0
  38. {softschema-0.1.4 → softschema-0.2.1}/LICENSE +0 -0
  39. {softschema-0.1.4 → softschema-0.2.1}/docs/publishing-npm.md +0 -0
  40. {softschema-0.1.4 → softschema-0.2.1}/examples/__init__.py +0 -0
  41. {softschema-0.1.4 → softschema-0.2.1}/examples/movie_page/__init__.py +0 -0
  42. {softschema-0.1.4 → softschema-0.2.1}/examples/movie_page/host_integration.py +0 -0
  43. {softschema-0.1.4 → softschema-0.2.1}/examples/movie_page/model.py +0 -0
  44. {softschema-0.1.4 → softschema-0.2.1}/examples/movie_page/movie-page.schema.yaml +0 -0
  45. {softschema-0.1.4 → softschema-0.2.1}/examples/parity/__init__.py +0 -0
  46. {softschema-0.1.4 → softschema-0.2.1}/examples/parity/model.py +0 -0
  47. {softschema-0.1.4 → softschema-0.2.1}/examples/parity/parity.schema.yaml +0 -0
  48. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/__init__.py +0 -0
  49. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/py.typed +0 -0
  50. {softschema-0.1.4 → softschema-0.2.1}/packages/python/src/softschema/registry.py +0 -0
  51. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_canonicalize.py +0 -0
  52. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_doc_topics_resolve.py +0 -0
  53. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_enforced_extras.py +0 -0
  54. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_errors.py +0 -0
  55. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_metadata_rules.py +0 -0
  56. {softschema-0.1.4 → softschema-0.2.1}/packages/python/tests/test_skill_mirror_drift.py +0 -0
  57. {softschema-0.1.4 → softschema-0.2.1}/packages/typescript/LICENSE +0 -0
  58. {softschema-0.1.4 → softschema-0.2.1}/pyproject.toml +0 -0
@@ -4,16 +4,16 @@ This repo teaches and implements the soft schema pattern.
4
4
 
5
5
  Start here:
6
6
 
7
- - [Softschema Guide](docs/softschema-guide.md): standalone concept and adoption guide
7
+ - [softschema Guide](docs/softschema-guide.md): standalone concept and adoption guide
8
8
  for humans and agents.
9
- - [Softschema Spec](docs/softschema-spec.md): exact language-neutral artifact format.
10
- - [Movie page example](examples/movie_page/README.md): complete Python-backed example.
9
+ - [softschema Spec](docs/softschema-spec.md): exact language-neutral artifact format.
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
13
  surface: Python/Pydantic (`softschema`, `softschema-py`) and TypeScript/Zod
14
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.
15
+ same canonical compiled JSON Schema, same validation results, so authoring an artifact
16
+ is identical regardless of which you run.
17
17
 
18
18
  For implementer reference (only when changing a package itself):
19
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: softschema
3
- Version: 0.1.4
3
+ Version: 0.2.1
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
@@ -28,8 +28,24 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  # softschema
30
30
 
31
+ Soft schemas: gradual, practical validation for Markdown/YAML artifacts that mix prose
32
+ and structured data—built for humans and coding agents.
33
+
31
34
  ## Quick Start
32
35
 
36
+ Try it anywhere, with nothing installed but [uv](https://docs.astral.sh/uv/) or Node.
37
+ Print the bundled example artifact and its compiled schema, then validate—the artifact
38
+ is fully self-describing, so no flags are needed:
39
+
40
+ ```bash
41
+ uvx softschema@latest docs example-artifact > spirited-away.md
42
+ uvx softschema@latest docs example-schema > movie-page.schema.yaml
43
+ uvx softschema@latest validate spirited-away.md
44
+ ```
45
+
46
+ (Or `npx softschema@latest ...` for the Node implementation; the two are
47
+ interchangeable.)
48
+
33
49
  To set up softschema in a repository with an agent, tell the agent:
34
50
 
35
51
  > Run `uvx softschema@latest --help` (for the Python implementation) or
@@ -47,13 +63,13 @@ flexible document context and machine-readable values.
47
63
  The idea is quite simple, but I’ve found it non-obvious enough that coding agents do not
48
64
  come up with this approach themselves.
49
65
 
50
- However if given the information and tools in this repo, soft schemas are unreasonably
66
+ However, if given the information and tools in this repo, soft schemas are unreasonably
51
67
  effective. Agents become far better at designing and building complex workflows that mix
52
68
  structured and unstructured data, such as document processing, data extraction,
53
69
  scientific or financial analyses, and many similar applications.
54
70
 
55
71
  **Soft schemas** are what we call the general practice.
56
- **Softschema** is the name of this repository’s Markdown-and-YAML spec and the matching
72
+ **softschema** is the name of this repository’s Markdown-and-YAML spec and the matching
57
73
  `softschema` CLI that implements it.
58
74
 
59
75
  ## How Do Soft Schemas Work?
@@ -135,60 +151,20 @@ Keeping prose and structured values in one artifact is more convenient and
135
151
  context-efficient. A reader (human or agent) has only one place to look, and information
136
152
  can stay as loose prose until a downstream consumer needs it in more formal schemas.
137
153
 
138
- ## What Is This Repo?
139
-
140
- This repo is simply:
141
-
142
- - A few documents for use by agents, including a [spec](docs/softschema-spec.md)
143
- defining soft schema file format conventions for Markdown documents with YAML
144
- frontmatter.
145
-
146
- - A small CLI (and library) that handles formatting, compilation, validation, and other
147
- common workflows on soft schema-style documents.
148
-
149
- The CLI can be used directly, as a library, or installed as a skill.
150
-
151
- For the full conceptual reference and adoption playbooks, see the
152
- [Softschema Guide](docs/softschema-guide.md).
153
-
154
- ## Two Synchronized Implementations
155
-
156
- softschema ships **two complete, fully supported implementations** with the same CLI and
157
- library surface:
158
-
159
- - **Python / Pydantic**: [`softschema`](docs/softschema-python-design.md) on PyPI (run
160
- as `softschema` or `softschema-py`).
161
- - **TypeScript / Zod**: [`softschema`](docs/softschema-typescript-design.md) on npm (run
162
- as `softschema` or `softschema-ts`).
163
-
164
- The TypeScript package is a **synchronized port** of the Python one, held to **exact
165
- behavioral parity**: equivalent CLI inputs, outputs, and flags; equivalent library APIs;
166
- the same canonical JSON Schema sidecar (content-identical, with an equal `schema_sha256`
167
- fingerprint over its canonical JSON); and the same engine-neutral validation results.
168
- Only idiomatic surface details differ (snake_case ↔ camelCase, Pydantic ↔ Zod).
169
- Authoring or validating an artifact is identical regardless of which you run, so a team
170
- can adopt either runtime, or both, without divergence.
171
-
172
- The two are **maintained in lockstep**: every behavior change lands in a shared
173
- golden-test corpus first, then in both packages, and CI fails if their outputs or
174
- compiled schemas drift.
175
- They release together under **the same version number** on PyPI and npm.
176
- See
177
- [Keeping Python and TypeScript in Parity](docs/development.md#keeping-python-and-typescript-in-parity)
178
- for the development process and the parity invariants CI enforces, and
179
- [Publishing](https://github.com/jlevy/softschema/blob/main/docs/publishing.md) for the
180
- synchronized release.
181
-
182
- ## Example Artifact Shape
154
+ ## The Artifact Shape
183
155
 
184
156
  The default shape is Markdown with YAML frontmatter.
185
- Use `softschema.contract` to name the contract for the enclosed payload:
157
+ The `softschema:` block is the self-description quartet: `contract` names the payload
158
+ contract, `schema` points at the compiled JSON Schema (relative to the document),
159
+ `envelope` names the payload key, and `status` sets validation strictness:
186
160
 
187
161
  ```markdown
188
162
  ---
189
163
  title: Spirited Away (2001)
190
164
  softschema:
191
165
  contract: example.movies:MoviePage/v1
166
+ schema: movie-page.schema.yaml
167
+ envelope: movie
192
168
  status: enforced
193
169
  movie:
194
170
  title: Spirited Away
@@ -197,153 +173,108 @@ movie:
197
173
  mpaa_rating: PG
198
174
  directors:
199
175
  - Hayao Miyazaki
200
- genres:
201
- - Animation
202
- - Adventure
203
- - Family
204
- synopsis: >
205
- Ten-year-old Chihiro and her parents stumble into a mysterious abandoned town
206
- that turns out to be a spirit world. After her parents are transformed into pigs,
207
- Chihiro must take a job in a magical bathhouse run by the witch Yubaba and find a
208
- way to break the spell so the family can return home.
209
- cast:
210
- - actor: Rumi Hiiragi
211
- character: Chihiro / Sen
212
- - actor: Miyu Irino
213
- character: Haku
214
- - actor: Mari Natsuki
215
- character: Yubaba
176
+ genres: [Animation, Adventure, Family]
216
177
  ratings:
217
- rotten_tomatoes:
218
- critics_percent: 96
219
- audience_percent: 96
220
- critic_review_count: 225
221
178
  imdb:
222
179
  score: 8.6
223
180
  total_votes: 850000
224
181
  ---
225
182
  # Spirited Away (2001)
226
183
 
227
- *Spirited Away* is Hayao Miyazakis animated fantasy about ten-year-old Chihiro, who
184
+ *Spirited Away* is Hayao Miyazaki's animated fantasy about ten-year-old Chihiro, who
228
185
  slips into a spirit world and takes a job in a bathhouse for the gods to free her
229
186
  parents from the witch Yubaba.
230
187
  It won the 2003 Academy Award for Best Animated Feature.
231
-
232
- Rotten Tomatoes shows a 96% Tomatometer from 225 critic reviews and a 96% Popcornmeter
233
- from the audience; IMDb users give it 8.6 out of 10 across more than 850,000 votes.
234
-
235
- <!-- The reader-facing body continues with prose and tables; see the full example. -->
236
188
  ```
237
189
 
238
190
  The YAML payload is authoritative; a consumer reads it.
239
191
  The Markdown body overlaps with it but is for human readers: the prose adds context like
240
- the film’s Academy Award (which no structured field carries), the YAML alone carries
241
- downstream fields such as `critic_review_count`, and the full example’s body mirrors
242
- some YAML fields as tables for the reader’s convenience.
192
+ the film’s Academy Award (which no structured field carries), and the full example’s
193
+ body mirrors some YAML fields as tables for the reader’s convenience.
243
194
 
244
- Only the `softschema` block and the chosen envelope key (`movie:` above) are
195
+ Only the `softschema` block and the declared envelope key (`movie:` above) are
245
196
  softschema’s concern.
246
- Additional top-level frontmatter keys, such as the `title:` above (or fields like
247
- `description:`, `tags:`, or any other host-specific metadata), are a separate concern.
248
- softschema neither forbids nor interprets them, so an artifact can coexist with whatever
197
+ Additional top-level frontmatter keys, such as the `title:` above (or `description:`,
198
+ `tags:`, or any other host-specific metadata), are a separate concern: softschema
199
+ neither forbids nor interprets them, so an artifact can coexist with whatever
249
200
  frontmatter conventions a static-site generator, doc indexer, or other tool already
250
- expects. When an artifact carries any such extra top-level key, the validator can no
251
- longer infer the envelope on its own; pass `--envelope` (or set `envelope_key` on the
252
- registered contract) to designate the payload.
253
-
254
- The example illustrates the structural variety a softschema artifact can carry:
255
- constrained integers (`release_year`, `runtime_minutes`), an enum (`mpaa_rating`
256
- restricted to `G`, `PG`, `PG-13`, `R`, `NC-17`, `NR`), lists of strings (`directors`,
257
- `genres`), a list of structured records (`cast`), and nested objects (`ratings`). The
258
- full artifact, model, and generated JSON Schema live under
259
- [examples/movie_page/](examples/movie_page/README.md).
260
-
261
- ## Contract IDs
262
-
263
- Recommended style:
264
-
265
- ```text
266
- namespace:UpperCamelCaseName/version
267
- ```
268
-
269
- Examples:
270
-
271
- - `example.movies:MoviePage/v1`
272
- - `example.docs:IncidentReview/v1`
273
- - `com.acme.docs:IncidentReview/1.0`
201
+ expects. Because the artifact declares `envelope: movie`, validation still needs no
202
+ flags.
274
203
 
275
- The ID names an artifact payload contract, not a required class or import path.
204
+ Every key after `contract` is optional; a minimal artifact carries `contract` alone and
205
+ binds its schema some other way (a `--schema` flag, or a host registry in library use).
206
+ Contract IDs follow an enforced shape, `[namespace:]Name[/version]`—for example
207
+ `example.movies:MoviePage/v1` or `com.acme.docs:IncidentReview/1.0`—naming a payload
208
+ contract, not a class or import path.
276
209
 
277
- ## Try the Python Package
210
+ ## Validate
278
211
 
279
- Install dependencies (see [Installation](docs/installation.md) for uv and Python setup):
212
+ A self-describing artifact validates with no flags; flags override the document when you
213
+ need to point a run elsewhere:
280
214
 
281
215
  ```bash
282
- uv sync --all-extras
216
+ softschema validate doc.md # uses the document's bindings
217
+ softschema validate doc.md --schema candidate.schema.yaml # try a different schema
218
+ softschema validate doc.md --envelope incident # designate the payload key
283
219
  ```
284
220
 
285
- Validate the example:
221
+ `validate` reports structural (JSON Schema) and semantic (Pydantic/Zod model) results
222
+ separately as deterministic JSON. Semantic validation loads a model with
223
+ `--model module:Class` (Python) or `--model path:export` (Zod)—note that `--model`
224
+ imports and executes local code, so use it only with trusted models; a compiled schema
225
+ via `--schema` executes nothing and is the safe path for untrusted input.
286
226
 
287
- ```bash
288
- uv run softschema validate examples/movie_page/spirited-away.md \
289
- --model examples.movie_page.model:MoviePage \
290
- --schema examples/movie_page/movie-page.schema.yaml \
291
- --envelope movie
292
- ```
227
+ ## Install
293
228
 
294
- `validate` reads `softschema.contract` and `softschema.status` from the document.
295
- `--envelope movie` designates the payload key, which the example needs because the
296
- artifact also carries a top-level `title:` that softschema does not interpret.
297
- When an artifact has exactly one non-`softschema` top-level key, that key is inferred as
298
- the envelope automatically and `--envelope` is unnecessary.
299
- `--contract` and `--status` override the corresponding `softschema:` fields.
229
+ Two supported ways to consume softschema; pick by use:
300
230
 
301
- Read the bundled docs from the CLI:
231
+ - **Pin it as a dependency** for projects, CI gates, and library use (reproducible,
232
+ fast, offline, and the only way to `import` it):
302
233
 
303
- ```bash
304
- uv run softschema docs --list
305
- uv run softschema docs --list --json
306
- uv run softschema docs guide
307
- uv run softschema docs example-artifact
308
- uv run softschema skill --brief
309
- ```
234
+ ```bash
235
+ uv add --dev softschema==0.2.1 # Python
236
+ npm install -D softschema@0.2.1 # Node (or: bun add -d)
237
+ ```
310
238
 
311
- The examples are plain files under `examples/`. The CLI can print them so an agent or
312
- human can copy from them, but it does not scaffold or mutate another project.
239
+ - **Zero-install** for one-off checks and agent bootstrap:
313
240
 
314
- Compile the example schema sidecar:
241
+ ```bash
242
+ uvx softschema@latest --help
243
+ npx softschema@latest --help
244
+ ```
315
245
 
316
- ```bash
317
- uv run softschema compile examples.movie_page.model:MoviePage \
318
- --contract example.movies:MoviePage/v1 \
319
- --out examples/movie_page/movie-page.schema.yaml
320
- ```
246
+ The rule of thumb: if softschema runs more than once, or in CI, or you import it—pin it.
247
+ For a quick check or an agent bootstrapping with nothing installed, use a zero-install
248
+ runner. See [Installation](docs/installation.md) for details, including the supply-chain
249
+ cool-off that makes `@latest` safe to recommend.
321
250
 
322
- ## Try the TypeScript Package
251
+ ## Use as a Library
323
252
 
324
- The TypeScript CLI takes the same arguments and emits byte-identical output.
325
- Validate the same artifact against the same language-neutral schema sidecar with a
326
- pinned zero-install runner:
253
+ Both packages expose the same surface (idiomatic per language).
254
+ Register contracts at startup and validate at file boundaries:
327
255
 
328
- ```bash
329
- npx softschema@latest validate examples/movie_page/spirited-away.md \
330
- --schema examples/movie_page/movie-page.schema.yaml \
331
- --envelope movie
256
+ ```python
257
+ from pathlib import Path
258
+ from softschema import Contract, Contracts, validate_artifact
259
+
260
+ registry = Contracts()
261
+ registry.register(Contract(id="mycorp.docs:IncidentReview/v1", model=IncidentReview,
262
+ envelope_key="incident"))
263
+ result = validate_artifact(Path("incident.md"),
264
+ contract_id="mycorp.docs:IncidentReview/v1",
265
+ registry=registry)
332
266
  ```
333
267
 
334
- The bundled docs and skill are served identically:
268
+ ```ts
269
+ import { validateArtifact } from "softschema";
335
270
 
336
- ```bash
337
- npx softschema@latest docs --list
338
- npx softschema@latest docs guide
339
- npx softschema@latest skill --brief
271
+ const result = validateArtifact("incident.md", contract);
340
272
  ```
341
273
 
342
- Semantic models are written in Zod instead of Pydantic; everything else (flags, result
343
- JSON, error records, and the compiled sidecar, down to its `schema_sha256`) matches the
344
- Python package exactly.
345
- See the [TypeScript Design](docs/softschema-typescript-design.md) doc for the Zod model
346
- shape and the full Python ↔ TypeScript API table.
274
+ A host registry’s bindings outrank the document’s own (`softschema.schema`/`envelope`),
275
+ so a document cannot silently redirect a host’s validation; a contract registered
276
+ without a schema path lets self-describing documents bind themselves.
277
+ See the [softschema Guide](docs/softschema-guide.md) for the full playbooks.
347
278
 
348
279
  ## Use as an Agent Skill
349
280
 
@@ -382,31 +313,40 @@ uvx softschema@latest skill --install
382
313
  Both mirrors carry a `DO NOT EDIT` marker.
383
314
  Re-run `skill --install` to refresh after upgrading the CLI.
384
315
 
385
- ## Repository Layout
316
+ ## Two Synchronized Implementations
386
317
 
387
- ```text
388
- docs/ guide, spec, package design (Python + TypeScript), and workflow docs
389
- examples/movie_page/ complete example with model, host integration, artifact, schema
390
- examples/parity/ cross-language parity fixture (Pydantic + Zod compile to one schema)
391
- packages/python/ Python/Pydantic implementation and tests
392
- packages/typescript/ TypeScript/Zod implementation and tests
393
- skills/softschema/ agent-facing usage guidance (shared SKILL.md source)
394
- tests/golden/ shared CLI golden corpus, run against both implementations
395
- ```
318
+ softschema ships **two complete, fully supported implementations** with the same CLI and
319
+ library surface:
320
+
321
+ - **Python / Pydantic**: [`softschema`](docs/softschema-python-design.md) on PyPI (run
322
+ as `softschema` or `softschema-py`).
323
+ - **TypeScript / Zod**: [`softschema`](docs/softschema-typescript-design.md) on npm (run
324
+ as `softschema` or `softschema-ts`).
396
325
 
397
- The root `pyproject.toml` builds the Python package from
398
- `packages/python/src/softschema`; `packages/typescript` builds the npm `softschema`
399
- package with bun. The shared golden corpus and the cross-language conformance test keep
400
- the two implementations byte-for-byte in sync.
326
+ The two are held to **exact behavioral parity**: equivalent CLI inputs, outputs, and
327
+ flags; equivalent library APIs; the same canonical compiled JSON Schema
328
+ (content-identical, with an equal `schema_sha256` fingerprint); and the same
329
+ engine-neutral validation results.
330
+ Every behavior change lands in a shared golden-test corpus first, then in both packages,
331
+ and CI fails if their outputs or compiled schemas drift.
332
+ They release together under the same version number on PyPI and npm.
401
333
 
402
- ## Development and Contributing
334
+ ## Further Reading
335
+
336
+ - [softschema Guide](docs/softschema-guide.md): the full mental model and adoption
337
+ playbooks.
338
+ - [softschema Spec](docs/softschema-spec.md): the exact artifact format and validation
339
+ rules.
340
+ - [Movie Page Example](examples/movie_page/README.md): the complete example backing the
341
+ snippets above.
342
+ - [Installation](docs/installation.md): pinned vs zero-install, uv and Node setup.
403
343
 
404
- See [Development](docs/development.md) for repo setup, common commands, CI checks,
405
- release workflow, and pointers to the installation and publishing docs.
344
+ ## Development and Contributing
406
345
 
407
- The Python and TypeScript implementations **must be kept in exact sync**. Any behavior
408
- change goes through the shared golden corpus first and then lands in both packages; see
409
- [Keeping Python and TypeScript in Parity](docs/development.md#keeping-python-and-typescript-in-parity).
346
+ Repo setup, common commands, CI checks, the parity process, and the release workflow
347
+ live in [Development](docs/development.md).
348
+ The Python and TypeScript implementations must be kept in exact sync: any behavior
349
+ change goes through the shared golden corpus first and then lands in both packages.
410
350
 
411
351
  <!-- This document follows common-doc-guidelines.md.
412
352
  See github.com/jlevy/practical-prose and review guidelines before editing.