Repair malformed JSON from language models and hand-written config.
Project description
laga
laga repairs malformed JSON and returns Python objects.
It is built for the real world: model output, hand-written config, copied snippets, and other almost-JSON text that is usually close enough to recover but not strict enough for json.loads.
Highlights
- Repairs common JSON mistakes such as trailing commas, missing commas, single quotes, unquoted keys, comments, fences, smart quotes, and truncated containers.
- Tries the standard library first, so valid JSON stays fast and strict.
- Keeps the public API small:
repair,repair_to_str,loads, andLagaError. - Ships with a CLI, JSONL support, type information, tests, docs, and CI.
Supported Versions
laga 0.1.6 supports Python 3.10 through 3.13.
Install
For normal use from PyPI:
python -m pip install laga
For local development from a checkout:
python -m pip install -e ".[dev]"
Quick Start
import laga
text = "{name: 'Ada', active: True, roles: ['admin', 'writer',],}"
data = laga.repair(text)
print(data)
print(laga.repair_to_str(text))
CLI
You can also use laga from the command line:
laga "{name: 'Ada', active: True, roles: ['admin',]}"
laga --strict '{"a": 1,}'
Use --strict when you want to reject ambiguous repairs instead of filling in gaps.
Use --pretty to format output for humans, --stdin to read from standard input, and --duplicate-keys error when duplicate keys should fail.
Use --input to read from a file, --output to write the repaired result back to disk, or --in-place to overwrite the input file directly.
Use --jsonl when each non-empty line is a separate JSON record and you want one repaired value per line.
laga --stdin --pretty
laga --input sample.txt --output fixed.json
laga --input sample.txt --in-place --pretty
laga --jsonl --stdin
laga --max-depth 64 --max-input-size 10000 --duplicate-keys error '{"a": 1}'
API
| Function | Returns | Description |
|---|---|---|
laga.repair(text, strict=False) |
Python object | Repairs malformed JSON and returns Python data. |
laga.repair_to_str(text, strict=False) |
str |
Repairs malformed JSON and returns normalized JSON text. |
laga.repair_jsonl(text, strict=False) |
list[object] |
Repairs newline-delimited JSON records and returns Python values. |
laga.repair_jsonl_to_str(text, strict=False) |
str |
Repairs newline-delimited JSON records and returns newline-delimited JSON text. |
laga.repair_file(path, strict=False) |
Python object | Reads a file and repairs its contents. |
laga.loads(text, strict=False) |
Python object | Alias for laga.repair. |
laga.LagaError |
Exception type | Raised when repair fails or input is unrecoverable. |
What It Repairs
| Rule | Before | After |
|---|---|---|
| Trailing comma | {"a": 1,} |
{"a":1} |
| Missing comma | {"a": 1 "b": 2} |
{"a":1,"b":2} |
| Single quotes | {'a': 'b'} |
{"a":"b"} |
| Unquoted keys | {name: "Ada"} |
{"name":"Ada"} |
| Python literals | {"ok": True, "none": None} |
{"ok":true,"none":null} |
| Comments | {"a": 1 // note\n} |
{"a":1} |
| Markdown fences | |
{"a":1} |
| Smart quotes | “a” |
"a" |
| Prose around JSON | Result: {"a":1} |
{"a":1} |
| Truncated structure | {"a": [1, 2 |
{"a":[1,2]} |
Strict Mode
strict=True is for validation workflows where you want laga to fail instead of guessing.
In strict mode, laga rejects ambiguous recoveries such as:
- missing commas between object members or array items
- unterminated objects or arrays
- other repairs that would require filling in structure the input did not clearly provide
Behavior Notes
json.loadsis still the best choice when you control the producer and the input is already valid JSON.- Duplicate keys use last-value-wins behavior, matching Python dict semantics.
- Use
duplicate_keys="error"when you want duplicate object members to fail instead of being merged. lagadoes not evaluate expressions or try to invent arbitrary JavaScript syntax.- The parser is intentionally conservative around malformed numbers and highly ambiguous text.
Quick Decision Guide
| Situation | Best choice |
|---|---|
| You control the producer and the input is valid JSON | json.loads |
| You have noisy LLM output, copied config, or prose around JSON | laga.repair |
| You have JSONL or line-delimited records to repair | laga.repair_jsonl |
| You need to repair a file directly | laga.repair_file |
| You want duplicate keys to fail | duplicate_keys="error" |
| You want a human-friendly result | repair_to_str(..., pretty=True) |
When To Use laga
Use laga when the input is noisy, user-facing, or generated by a model and you need a predictable repair step before parsing.
Use json.loads when correctness and strictness matter more than recovery.
Development
make install
make lint
make typecheck
make test
make build
Project Links
- Documentation: docs/index.md
- API details: docs/api.md
- Usage examples: docs/usage.md
- Contributing guide: CONTRIBUTING.md
Citation
If you use laga in academic work, research notes, or other formal writing, please cite the repository using the metadata in CITATION.cff.
Suggested citation format:
Laitinen-Fredriksson Lundström-Imanov, G. O. Y. (2026). laga (Version 0.1.6) [Computer software]. https://github.com/olaflaitinen/laga
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file laga-0.1.6.tar.gz.
File metadata
- Download URL: laga-0.1.6.tar.gz
- Upload date:
- Size: 25.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1861980d9d58ae7dc86d8f10b6827bd19b33f34361a1af4aea344c71b5ac080b
|
|
| MD5 |
e1886fec154ce893b9b3f388c1390a63
|
|
| BLAKE2b-256 |
d2d24dec0d9aa95c0bf5c4d3234d5688d133c9798c8d8fc17d57d9f33cb1979a
|
Provenance
The following attestation bundles were made for laga-0.1.6.tar.gz:
Publisher:
release.yml on olaflaitinen/laga
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
laga-0.1.6.tar.gz -
Subject digest:
1861980d9d58ae7dc86d8f10b6827bd19b33f34361a1af4aea344c71b5ac080b - Sigstore transparency entry: 2247418760
- Sigstore integration time:
-
Permalink:
olaflaitinen/laga@d609d588ee33142b0f95e64d7f0a098facbe3667 -
Branch / Tag:
refs/tags/v0.1.6 - Owner: https://github.com/olaflaitinen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d609d588ee33142b0f95e64d7f0a098facbe3667 -
Trigger Event:
push
-
Statement type:
File details
Details for the file laga-0.1.6-py3-none-any.whl.
File metadata
- Download URL: laga-0.1.6-py3-none-any.whl
- Upload date:
- Size: 12.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
955e63a35d9d16cd2f4f48dd454b43f175a55dc7cc735e329b6a39f3b3002173
|
|
| MD5 |
df4d9d5edb8ab08151774f900af10345
|
|
| BLAKE2b-256 |
3c2b2e6ee9f7202d430b558b3df3a867724d3e9554c43ca185ea258b862a54f0
|
Provenance
The following attestation bundles were made for laga-0.1.6-py3-none-any.whl:
Publisher:
release.yml on olaflaitinen/laga
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
laga-0.1.6-py3-none-any.whl -
Subject digest:
955e63a35d9d16cd2f4f48dd454b43f175a55dc7cc735e329b6a39f3b3002173 - Sigstore transparency entry: 2247418789
- Sigstore integration time:
-
Permalink:
olaflaitinen/laga@d609d588ee33142b0f95e64d7f0a098facbe3667 -
Branch / Tag:
refs/tags/v0.1.6 - Owner: https://github.com/olaflaitinen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d609d588ee33142b0f95e64d7f0a098facbe3667 -
Trigger Event:
push
-
Statement type: