prompt-crafter
Say what the picture must contain. Check that it does. Refuse when it doesn't.
A generative image pipeline will happily hand you a hero with the wrong face, the wrong palette and none of the faction's markings — and report success, because nothing looked. prompt-crafter replaces the opaque prose prompt with a typed contract of depictable claims, uses that same list twice — once to write the prompt, once to check the pixels — and blocks the asset when a required claim is not there.
The one idea: the contract's atom list is the same list used twice. Writing the prompt and checking the result read from one source, so the thing you asked for is the thing that gets verified. That is what closes the loop an opaque prompt leaves open.
Install
pip install prompt-crafter
pcraft --help
The distribution is prompt-crafter; the import package and the command are pcraft. Requires
Python 3.11+. The core's only runtime dependency is pydantic.
pcraft demo # the whole loop end-to-end, no GPU, deterministic stubs
pcraft gate <image> # check an image against a contract
pcraft replay <record> # re-read a bound asset's provenance receipt
What a contract looks like
Not a prose prompt. A list of atomic, depictable, individually checkable claims:
must_have— a garment, a palette, a silhouette, a sigil. Each names which gate tier verifies it, a severity, and optionally adepends_onedge, so there is no point verifying the colour of an axe that is not there.must_not— anti-constraints, verified as absence on the pixels. Not a negative prompt: negative prompts leave residual features and fall to paraphrase.identity_ref— a reference plate. Identity is conditioning, not tokens. Anatomical text makes a diffusion model render a specimen; a reference image binds the specific face.
Contracts inherit — a character extends a faction — and inheritance is fail-closed: a child may raise a requirement, never relax or silently drop one it inherited.
The exit code is the point
| exit | meaning |
|---|---|
0 |
the gate ran and every required atom passed |
1 |
bad arguments or a malformed contract |
2 |
it ran, and a required atom failed |
3 |
it ran, and the result is unconfirmed — the human band |
4 |
it could not run |
The 2 / 4 split is the whole design. "I could not check" and "I checked and it is bad" are
different facts. Merging them is why browsers soft-fail certificate revocation, and why
monitoring standards have carried a distinct unknown verdict since the 1990s. Every gate
transcript also reports how many required tiers actually executed, so a gate that quietly stopped
checking cannot read as a pass.
The verifier is always a different model family from the generator, enforced by a guard that refuses to run otherwise. CLIPScore is not used as the gate metric — it behaves as a bag of concepts, blind to which attribute belongs to which object.
Honest status
v0.2.1 — the core is real; the GPU path has never run here.
- 105 tests passing, GPU-free and deterministic. The whole suite runs against a mock generator and verifier, which is what proves the plugin boundary holds.
- The eleven compound decision points in the core are mutation-tested — 20 of 21 mutants killed, and the survivor is named rather than hidden.
- The
[image]extra has never executed on the machine this was developed on.bind --no-mockrefuses with a missing-dependency error. Everything below the plugin boundary is unproven by measurement. - The sprite sub-gate's thresholds are hardcoded defaults with no calibration — no holdout, no citation. Treat them as placeholders.
- Pre-1.0 deliberately, and a test enforces it. Promotion should follow evidence, not a version bump.
Trust
No credentials are read, stored or transmitted. No telemetry — there is no opt-out because
there is nothing to opt out of. The core imports no networking library at all; the optional
extras reach a model host by their nature, and installing them is a choice. File operations are
not sandboxed: --records-dir and --db write where you point them, deliberately, for a
local-first tool.
Deliberate refusals carry a code, a message and a hint, and raise rather than assert — so
-O cannot delete them, and the suite runs a second time under -O to prove it.
Documentation and handbook → · Source · Changelog
MIT
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 prompt_crafter-0.2.1.tar.gz.
File metadata
- Download URL: prompt_crafter-0.2.1.tar.gz
- Upload date:
- Size: 522.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d81c8cf2f73f695135e3f0001c400abc096028a9cd8dd77b41c2bcf8742cb7ea
|
|
| MD5 |
50629509d7d79a14a1ce7889f2d9e6c7
|
|
| BLAKE2b-256 |
6fc2526487f9b5a64cd2f9b85a03518e798ba7129c87fdfb18711f12051759f5
|
Provenance
The following attestation bundles were made for prompt_crafter-0.2.1.tar.gz:
Publisher:
release.yml on mcp-tool-shop-org/prompt-craft
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prompt_crafter-0.2.1.tar.gz -
Subject digest:
d81c8cf2f73f695135e3f0001c400abc096028a9cd8dd77b41c2bcf8742cb7ea - Sigstore transparency entry: 2500454483
- Sigstore integration time:
-
Permalink:
mcp-tool-shop-org/prompt-craft@561b2e75800872b937d4c8ecda0e3cda42068f1a -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/mcp-tool-shop-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@561b2e75800872b937d4c8ecda0e3cda42068f1a -
Trigger Event:
release
-
Statement type:
File details
Details for the file prompt_crafter-0.2.1-py3-none-any.whl.
File metadata
- Download URL: prompt_crafter-0.2.1-py3-none-any.whl
- Upload date:
- Size: 164.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74f0abf2ce0a2187e09b7b6afbe387297cf1dc607d41575cb77a70c1d5df1c4c
|
|
| MD5 |
63909a9a3631b1236cddb8189ffdbc34
|
|
| BLAKE2b-256 |
1bf3a18946ce999b4a5629b240f2ba212252db174b88edf6fc260d2fd75b85bb
|
Provenance
The following attestation bundles were made for prompt_crafter-0.2.1-py3-none-any.whl:
Publisher:
release.yml on mcp-tool-shop-org/prompt-craft
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prompt_crafter-0.2.1-py3-none-any.whl -
Subject digest:
74f0abf2ce0a2187e09b7b6afbe387297cf1dc607d41575cb77a70c1d5df1c4c - Sigstore transparency entry: 2500454491
- Sigstore integration time:
-
Permalink:
mcp-tool-shop-org/prompt-craft@561b2e75800872b937d4c8ecda0e3cda42068f1a -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/mcp-tool-shop-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@561b2e75800872b937d4c8ecda0e3cda42068f1a -
Trigger Event:
release
-
Statement type: