Skip to main content

Histos

Hijacked. Still bounded.

usehistos.dev

Deterministic authorization for AI agent tool calls — before execution and after return. The model proposes. Your policy decides.

Histos puts an in-process security boundary around the tools an agent can call. It does not guess whether a prompt is malicious. It enforces one narrow loop even when the model is manipulated:

  1. Authorize the input — tool, arguments, principal and trusted resource facts.
  2. Execute only within policy — or deny / require confirmation before side effects.
  3. Constrain the output — project and redact before it returns to the model.

No proxy, model or service is required. The core has zero runtime dependencies, works with sync and async tools, and keeps ordinary policy evaluation in-process. It is deliberately a small Python enforcement layer, not an identity platform, sandbox or fleet-governance suite. Audit, coverage, tool import and drift detection make that boundary reviewable and deployable.

Why this exists

A stronger prompt can reduce the chance of a bad decision. It cannot authorize a payment, prove tenant ownership or prevent a forbidden tool call from executing. Histos treats model input, retrieved documents and tool output as untrusted, then checks the action against policy written before the agent encountered them.

model / conversation / retrieved content / tool output   untrusted, variable
────────────────────────────────────────────────────────────────────────────
policy + authenticated principal + trusted resource data trusted boundary

This is enforcement, not prompt-injection detection. Detection asks whether content looks dangerous; Histos asks what the agent is allowed to do regardless. Its schema, RBAC, resource and binding checks are deterministic for their inputs; resource lookups, stateful limits, clocks and human approval remain runtime inputs.

See the boundary hold

The repository contains five runnable demos: a LangChain clinic receptionist, a LangGraph accounts-payable workflow, a framework-free on-call agent, an MCP tool rug pull, and a mediation harness. Each attack is judged from actual datastore effects, not from what the assistant claimed it did.

scenario without Histos with a complete policy
poisoned clinic note redirects an SMS patient data sent off-site recipient rebound to the authenticated patient
invoice quietly swaps the supplier IBAN 14,200 PLN sent to the wrong account payee denied against trusted supplier data
injected runbook requests zero replicas and a production deploy service damaged and an invented version deployed arguments and resource state keep production unchanged
MCP vendor rewrites a tool description after review ordinary schema diff is silent description drift makes the CI command exit 1

In the controlled qwen2.5:7b runs, 6 of 11 attacks damaged the competent baseline and 0 of 11 damaged the fully mediated version. Those model-driven figures were measured manually at temperature 0; they are evidence from these scenarios, not a general benchmark. A larger model avoided some baseline attacks, while the policy bounds remained deterministic. The clinic policy also demonstrates a real product cost: binding the SMS recipient removes caller-selected delivery. The full methods, raw distinctions and partial-wiring failure are documented in the demo report.

Install

pip install "histos[yaml]"

Requires Python 3.12 or newer. The yaml extra adds PyYAML; JSON policies use only the standard library. To see a hijacked call remain bounded with no model or infrastructure, clone the repository and run python examples/makeRefund_demo.py. The adversarial applications are in demo/.

Write a policy

A policy is YAML or JSON. This is a complete, enforceable YAML policy — not a sketch:

# yaml-language-server: $schema=https://usehistos.dev/spec/policy-0.1.schema.json
schema_version: histos.policy/0.1
policy_id: support-search
version: "1"

tools:
  search_docs:
    access: read
    args:
      query: {type: string, min_length: 1, max_length: 500}
    returns:
      title: {type: string}
      snippet: {type: string}
    output:
      project: true
      strict: true

roles:
  support:
    allow: [search_docs]

Unknown tools, roles and arguments deny by default. Validate the document, review the missing security decisions, then exercise one call without running the tool:

histos validate security.policy.yaml
histos review security.policy.yaml
histos explain security.policy.yaml search_docs \
  --role support --args '{"query":"refund policy"}'

Load the same file around the callable your agent receives:

from histos import Principal, protect, use_principal

def search_docs(query: str):
    return {"title": "Refunds", "snippet": "Refunds require a receipt."}

guarded = protect([search_docs], policy="security.policy.yaml")

with use_principal(Principal(role="support", identity="user-42")):
    result = guarded.tools["search_docs"](query="refund policy")

Set the Principal in trusted host code from an authenticated session or workload identity — never from model output or a tool argument. For a real tool set, import its argument and return shapes instead of retyping them, then author the decisions schemas cannot know: grants, ownership, trusted bindings, limits, confirmation and output. Follow the policy-writing guide, use the seven worked policies, or run the complete quickstart.

A production adoption path

Import tool shapes from MCP, OpenAI tools, OpenAPI, JSON Schema or Python signatures. Author what those schemas cannot know — roles, ownership, trusted bindings, confirmation and output rules. Run histos review and histos coverage, calibrate in mode="observe", then enforce with a durable audit sink and drift check in CI.

Worked policies for RAG, refunds, outbound email, MCP and deployments live in the policy gallery.

Read this before production

Histos is defense in depth, not a sandbox and not a replacement for backend authorization.

  • Every execution path must receive the wrapped callable. A raw tool retained or registered elsewhere is a bypass; coverage sees only the surface you declare.
  • Principal, resource facts, confirmation and policy are trusted host inputs. Histos does not replace backend authorization, sandbox compromised code or undo side effects before a post-call check.
  • Histos does not understand intent or stop unsafe workflows composed from separately allowed calls. Limits and built-in approvals are process-local; the default audit sink is memory-only.
  • The complete joined argument text is limited to 1 MiB by default and can be raised with input_budget=. A field using pattern is limited to 4,096 characters because it runs through Python's backtracking regex engine; unpatterned text is not.

The exact guarantee, residual object-inspection limits and safe deployment patterns are in SECURITY.md.

Status and documentation

Histos is an alpha API implementing Histos Policy Format Draft 0.1. The Python engine, policy format, CLI, conformance corpus, LangChain/LangGraph adapters and tool definition import/drift workflow exist today. A hosted control plane, JavaScript runtime and dedicated MCP enforcement product do not.

Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

histos-0.1.1.tar.gz (384.1 kB view details)

Uploaded Source

Built Distribution

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

histos-0.1.1-py3-none-any.whl (303.4 kB view details)

Uploaded Python 3

File details

Details for the file histos-0.1.1.tar.gz.

File metadata

  • Download URL: histos-0.1.1.tar.gz
  • Upload date:
  • Size: 384.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for histos-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d9d57cf1ac502ab7827d2de84e39f731457faa82e327d075a098eacbf6ec73af
MD5 984019bce5530969850dc5198d06dd0e
BLAKE2b-256 aabc80bddb78564eba1c6fa516dfa1444458feba2f832e3f41e904c71ba39820

See more details on using hashes here.

Provenance

The following attestation bundles were made for histos-0.1.1.tar.gz:

Publisher: release.yml on Szesnasty/histos

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

File details

Details for the file histos-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: histos-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 303.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for histos-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3c35453467c4f25954e4d28297f06af46cb80cf70100ce1e8accaf8737e378c9
MD5 0610fcc94e548e953a4d539ce66e6864
BLAKE2b-256 2246be68b8d13e93903c562b3667dcd55e72655516d825183aa61b581b87e329

See more details on using hashes here.

Provenance

The following attestation bundles were made for histos-0.1.1-py3-none-any.whl:

Publisher: release.yml on Szesnasty/histos

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 Sentry Error logging StatusPage Status page