Signato: information barriers for the age of AI, a deterministic and local confidentiality chamber (core: johari_guard)
Project description
Signato
Information barriers for the age of AI: a deterministic, local confidentiality chamber for operations with mandatory internal walls.
Between two confidentiality perimeters, nothing crosses directly: every outbound event stops at the chamber and is checked before it passes. Signato is the name of the product and the pip package; import signato and import johari_guard expose the SAME API (1:1 alias since v0.4.0 — the historical technical name stays valid so integrations do not break). Public integration guides, the adapter contract, and synthetic examples: https://github.com/Signato-ai/signato-integrations
The pain
A family office runs with several advisors on parallel workstreams: the succession lawyer, the bank renegotiating the debt, the investment advisor, the accountant. Each may only know their own front. Today that wall lives in the head of the principal and the team, and a single email, draft, or AI prompt to the wrong recipient breaks years of segregation. With AI assistants drafting communication at scale, the risk is no longer human but structural: the tool that writes faster also leaks faster.
What it does
johari-guard turns the confidentiality matrix into executable configuration. You declare in YAML who must NOT know what (perimeters: people with aliases, blocked topics with keywords, enforcement mode) and the library checks every outbound event, crossing person against subject in the same text. A hard perimeter denies the operation; a soft perimeter allows it with a warning. Beyond the internal crossing, the egress-warn layer (v0.8.0) flags when a sensitive subject is heading to a destination outside the list of who may receive it: the internal wall plus a door alarm. Every decision stays auditable in append-only JSONL telemetry. Person detection by word boundary (no substring false positives), subject by keyword, all case-insensitive, with a configurable failure posture (fail-open for gradual rollout, fail-closed for critical paths). The included adapter plugs into Claude Code's PreToolUse hook contract; the core is host-agnostic.
Quickstart
from johari_guard import Guard
guard = Guard("config/exemplo-family-office.yaml")
v = guard.check(
"Abel, we need to talk about the purchase offer for the company.",
target="draft-email-abel.md",
)
if not v.allowed:
print(f"blocked [{v.perimeter}]: {v.reason}")
As a Claude Code hook (settings.json, PreToolUse):
JOHARI_GUARD_CONFIG=/path/matrix.yaml \
JOHARI_GUARD_TELEMETRY=/path/telemetry.jsonl \
python3 -m johari_guard.adapters.claude_code
Battle-tested
Extracted from a mechanism with real telemetry and a suite of 55 scenarios in production since 05/2026, protecting confidentiality perimeters in a real multi-advisor operation. This package is the machinery, fully separated from the data: the example matrix is 100% synthetic and the library knows no real perimeter.
Since 2026-07-03 the originating production runs ON this library (roadmap phase 2): the person×subject detection engine of the real mechanism is this package's Guard, with the real matrix delivered as external config — continuous dogfooding, a 55-scenario regression gate on every change, and a post-release telemetry observation window.
CLI signato
After pip install ., the signato command is available with 13 subcommands:
# guided onboarding (v0.5): a business-language interview that generates a
# matrix + derived scenarios, runs the lint, and closes with a real block
# in front of you. Resumable; never overwrites without confirming; 100% local.
signato init
signato init --dir ./my-operation --fresh
signato init --import contacts.vcf # assisted migration: suggests people from your export (.csv/.vcf)
# fast self-service onboarding (< 5 min): shows a real block on synthetic data FIRST,
# then asks the minimum (one person + one subject) and writes matrix.yaml + scenarios.yaml.
# It closes by pointing your agent at the wall: the absolute matrix path, the
# JOHARI_GUARD_CONFIG line, and a ready-to-paste mcpServers block; never overwrites
# an existing ~/.signato/matrix.yaml. Never license-locked (an activation surface).
signato quickstart
# signato studio: the SAME onboarding in screens, in the browser (a 127.0.0.1 server from the
# package itself, pure stdlib; draft shared with init — start in one, finish in the other)
signato studio
# see in 1 minute how the library works (100% synthetic data)
signato demo
# check text or a file — exit 1 if BLOCK, 0 if ALLOW/SOFT, 2 on a configuration error
signato check --matrix matrix.yaml 'Dr. Araujo, purchase offer for the company...'
signato check --matrix matrix.yaml --file email.txt
# Retroactive Exposure Scan: point it at a local mailbox export (.eml/.txt/.mbox
# file, or a directory of them) and it checks every message against the matrix,
# streaming — never loads the whole mailbox in memory. It is a REPORT, not a
# gate (exit 0 even when exposure is found; non-zero only on a real I/O error).
# It never prints the protected content: only aggregate counts by perimeter,
# the same shape as `signato report`. Tolerant of dirty real-world mail
# (mismatched charset, malformed headers, unescaped mbox delimiters, forwarded
# messages nested as message/rfc822) — a message that cannot be parsed cleanly
# is flagged `degraded` and still counted, never dropped silently. Attachments
# are read as metadata only (filename/type/approximate size); the binary
# payload itself is never decoded. `.pst` is out of scope for the parser
# itself — convert it to `.mbox` first (e.g. with libpst) or export `.eml`.
signato scan --matrix matrix.yaml exported-mailbox.mbox
signato scan --matrix matrix.yaml ./exported-inbox/
# validate the matrix structure (coded anti-patterns: alias with notes, generic keyword, duplicate key, empty triggers, a subject that does not block its own name, and more)
signato lint --matrix matrix.yaml
# runner for declarative YAML scenarios — PASS/FAIL output per scenario
signato test --matrix matrix.yaml --scenarios scenarios.yaml
# JSONL telemetry summary with date filters and a per-mode/perimeter breakdown
# (--since/--until/--month are the English flags; --inicio/--fim/--mes stay accepted as aliases)
signato report --telemetry events.jsonl --since 2026-01-01 --until 2026-06-30
# value report for the closed month, compared with the previous month (v0.7)
signato report --telemetry events.jsonl --month 2026-06
# matrix snapshot + diff vs the previous trail + append-only record for audit
signato attest --matrix matrix.yaml --log attestations.jsonl
signato attest --matrix matrix.yaml --log attestations.jsonl --dry-run
# what-if BEFORE changing the matrix (v0.4): replay of history and/or scenario diff
signato simulate --telemetry events.jsonl --remove-perimeter wall-x --soften wall-y
signato simulate --matrix current.yaml --proposed new.yaml --scenarios scenarios.yaml
# exit 1 when the proposal LOOSENS any verdict (good for a matrix-change CI)
# license (commercial layer, SOFT enforcement): status auto-provisions a local 30-day trial;
# no license state turns off the wall mid-operation; after day 30 without a plan, verification commands refuse to run (never fail open)
signato license status
signato license activate --token SIG1.<payload>.<signature> # installs a paid license verified offline
# MCP server over stdio: exposes the chamber as three MCP tools (check_confidentiality,
# lint_matrix, run_matrix_tests) for AI-native agents that discover tooling via registries.
# The SDK is an optional extra (pip install "signato[mcp]"); the core stays PyYAML-only, and
# without the extra `signato mcp` prints one clean line + exit 1 (never a traceback).
signato mcp
Test scenarios format (scenarios.yaml):
matrix: path/to/matrix.yaml # optional if passed via --matrix
scenarios:
- name: block-advisor-a-with-sale-topic
payload: "Advisor A, purchase offer approved."
expected: block
- name: allow-subject-without-person
payload: "Purchase offer approved by the board."
expected: allow
- name: warn-advisor-c-with-wealth
payload: "Advisor C, investment portfolio available."
expected: soft
Installation and dependencies
PyYAML and stdlib, nothing else. The library is standalone: it imports nothing from outside its own package.
pip install signato # from PyPI (recommended)
pip install . # from a source checkout, same result
pip install ".[wizard]" # optional: arrows/checkbox in `signato init` (questionary)
pip install ".[license]" # optional: verifies a signed paid license (cryptography); trial and core do not need it
signato demo # quick smoke test
python -m unittest discover -s tests # full suite (830 tests — CLI + guard + governance + wizard + studio + templates/report + license + billing)
Dev note (interpreter): the suite requires PyYAML (and, for the optional tests,
cryptography/questionary). Use a Python that has them installed; a "bare" interpreter without PyYAML gives an import error, not a real product failure. Thestudiotests bind to 127.0.0.1 and are skipped in an environment that denies bind.
API
Guard.check(text, target) -> Verdict is the path with a failure posture (fail-open/fail-closed). Guard.egress_check(text, target, channel) -> Verdict (v0.8.0) is the outbound surveillance layer: it warns (SOFT, mode="egress-soft", never blocks) when a sensitive subject goes to a destination outside the trusted list, with the config in the matrix's egress section (trusted_recipients, generic_domains). For hosts with even more custom layers, the pure helpers Guard.people_in(text, target) and Guard.topic_hits(content, topics) expose the raw detection — no telemetry, and an unavailable matrix raises MatrixError (the failure posture stays with the caller).
Governance in the core (v0.4 — import signato is a 1:1 alias of johari_guard):
- Audited wall-crossing:
Guard(config, override_store=OverrideStore("overrides.jsonl"))— a HARD deny whose violations are ALL covered by live overrides becomes an audited allow (Verdict.is_override,Verdict.override_ids, telemetrymode="override"). Overrides are created byOverrideStore.create(pessoa_alias, topico, justificativa, escopo, ttl_hours, criado_por)(the API keeps its original identifiers): justification required, scopeproximo_envio(single-use) orate_ts, a 72h cap validated on creation AND on read (a forged record in the file does not escape). Append-only JSONL trail, event-sourcing. - Attestation as an API:
attest(matrix_path, log_path)→ canonical snapshot + hash + diff vs the last entry + a record in the trail (AttestResult);history(log_path)reads the trail. The regulated-market pattern (periodically attesting that the standing wall is the intended one), callable by cron. - What-if simulation:
replay(events, remove_perimeters, soften_perimeters)reprocesses historical verdicts under the proposed change;scenario_diff(current, proposed, scenarios)runs the declarative suite on both matrices and returns each verdict that changes (with aloosenedflag). Honest limit: adding a new keyword requires scenarios — the telemetry does not store content (privacy by design). - Embeddable onboarding (v0.5):
run_wizard(io=None, out_dir=".", fresh=False)runs the same interview assignato initfrom inside a host; theioparameter accepts a custom backend (the test one runs the whole interview without a TTY).derive_scenarios(matrix_dict)derives and VALIDATES scenarios from any matrix programmatically.
Roadmap
Phase 2 (COMPLETED 2026-07-04): the originating internal mechanism imports this library (production is the first client); telemetry gate + internal suite of 55 scenarios passed, staged rollout in production with wall-crossing, accent normalization, and a semantic egress layer on the host.
Phase 3: adapters for other hosts (email gateway, chat/LLM middleware, document CI), keeping the person×subject core intact and the Verdict contract as the single interface.
mcp-name: io.github.Signato-ai/signato
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
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 signato-0.14.0-py3-none-any.whl.
File metadata
- Download URL: signato-0.14.0-py3-none-any.whl
- Upload date:
- Size: 193.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bbf058dfda3372bd35911a72ac04f276d5ae04a4c15c2710e5605a35cffd6251
|
|
| MD5 |
48f29ae134e5529849341be11244d0f7
|
|
| BLAKE2b-256 |
c2bf7e2c154045e3df77ca374759a7003eb8a1364c325f013f4f326259287b04
|