Skip to main content

Reversible prompt-context restoration with audit trails

Project description

jabr (الجبر) — Reversible Prompt-Context Restoration

Part of the Mizan stack — the Arabic-first reliability scale for AI agents.

License: MIT Python 3.10+ Tests: 31 passing

Reversible. Audited. Deterministic. The Restore operation as a standalone primitive for AI agent pipelines.


What it does

Takes an under-specified prompt and a context, returns the prompt with implicit terms made explicit, plus a full audit trail. The original prompt is always recoverable from the output.

from datetime import datetime, timezone
from jabr import restore, unrestore, RestorationContext

ctx = RestorationContext(
    now=datetime(2026, 4, 25, 14, 30, tzinfo=timezone.utc),
    referents={"her": "Alice"},
    defaults={"channel": "#engineering"},
)

result = restore("tell her tomorrow to post in <channel>", ctx)

print(result.output)
# tell her[[jabr:abc123:pronoun:Alice]] tomorrow[[jabr:def456:date:2026-04-26]]
# to post in <channel>[[jabr:ghi789:default:#engineering]]

# Reversible
assert unrestore(result.output, result.trace) == "tell her tomorrow to post in <channel>"

Design properties

The library guarantees four properties:

  1. Reversibility. unrestore(restore(p, ctx).output, trace) == p for any (p, ctx). Verified by 31 tests including round-trip property tests.

  2. Tag-only insertion. Every added term is bracketed with [[jabr:<id>:<kind>:<value>]]. Original characters are never modified, only interspersed with tags.

  3. Trace integrity. Every tag in the output has a corresponding entry in the trace. unrestore() with a wrong trace raises RestorationError.

  4. Determinism. Given the same (prompt, context, resolvers), the output is byte-identical across runs.

Why this matters

In modern LLM agent pipelines, prompts are routinely rewritten, summarized, and "expanded" silently. The original cannot be recovered. Debugging is dream interpretation.

jabr makes that explicit. Every restoration is tagged, every tag is in the trace, every trace entry has provenance (source, confidence, original span). When the agent does something unexpected, you can replay the input through the same restoration and see exactly what was added.

Built-in resolvers

Resolver What it handles Confidence
DateTimeResolver today, tomorrow, yesterday, this morning/afternoon/evening, next/last , now 0.85–1.0
PronounResolver he/she/it/they/etc., resolved against explicit context.referents 1.0
DefaultResolver <placeholder> and @PLACEHOLDER resolved against context.defaults 1.0
QuantityResolver a few, several, many, a couple, lots of → numeric ranges 0.5–0.85

Add your own resolver by implementing the Resolver Protocol:

from jabr import Resolver, RestorationEntry, RestorationContext

class MyResolver:
    name = "my_domain"
    def find(self, input: str, context: RestorationContext) -> list[RestorationEntry]:
        ...

CLI

# Restore
jabr restore --prompt "tell her tomorrow" --context ctx.json

# Restore with system clock
jabr restore --prompt "ping me tomorrow" --now system

# Round-trip verify
jabr roundtrip --prompt "tomorrow morning" --now system

# Unrestore (recover original from output)
jabr unrestore --output "[output with tags]"

Where ctx.json looks like:

{
  "now": "2026-04-25T14:30:00+00:00",
  "timezone": "UTC",
  "referents": {"her": "Alice"},
  "defaults": {"channel": "#engineering"}
}

Install

pip install -e .

Tests

pytest tests/ -v

31/31 pass on Python 3.10+. No runtime dependencies.

What it is not

  • Not an LLM-powered prompt rewriter. There is no model in jabr. All resolvers are deterministic regex/dict-based functions.
  • Not a coreference-resolution library. Pronoun restoration only happens when an explicit referent map is supplied. There is no inference from prior conversation.
  • Not a guesser. If a term cannot be resolved (e.g., "tomorrow" without a now), jabr does nothing. Silence is the correct behavior on missing context.

Structure

jabr/
├── jabr/
│   ├── __init__.py       Public API
│   ├── core.py           restore() + unrestore() + dataclasses
│   ├── resolvers.py      4 built-in resolvers
│   └── cli.py            command-line interface
├── tests/
│   ├── test_core.py      core property tests
│   └── test_resolvers.py resolver-specific tests
├── pyproject.toml
├── README.md
├── LICENSE
└── FAILURES.md

Failure modes

See FAILURES.md for the honest list of what this library does not handle.

License

MIT.

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

jabr-0.1.0.tar.gz (18.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jabr-0.1.0-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

Details for the file jabr-0.1.0.tar.gz.

File metadata

  • Download URL: jabr-0.1.0.tar.gz
  • Upload date:
  • Size: 18.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for jabr-0.1.0.tar.gz
Algorithm Hash digest
SHA256 90657697d890d9fd42b66e78f89601569f90893e3ddf747f946fa26f42e83e1d
MD5 62e1e1a06bfac2c03e179b4283392e24
BLAKE2b-256 13c54462b5c31b62e0d9ea7773273c4ebc381273f98ccb63643663a394756b57

See more details on using hashes here.

Provenance

The following attestation bundles were made for jabr-0.1.0.tar.gz:

Publisher: release.yml on Moshe-ship/jabr

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jabr-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: jabr-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for jabr-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 78456aa2ebb7de0ee6bacd6e20ec3424c268308925e7f100228e69b30c49901b
MD5 6d663d0cfb4337c25857a15e1f62219a
BLAKE2b-256 074ea9171549ba0b40a7b0a15e6d55f291adaebdcb01744f8aa0d5423d2cb5a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for jabr-0.1.0-py3-none-any.whl:

Publisher: release.yml on Moshe-ship/jabr

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page