Skip to main content

Overwing

Guardrails for LLM output, in one line.
OpenAI Agents SDK guardrails, LangChain runnables and callbacks, and a typed client. Also: Atlas user-agent lookups with no key, and Tower for agents operating legacy systems. Every message gets a pass / fail / review verdict with calibrated confidence before it reaches your user.

PyPI CI API reference agents welcome


pip install overwing               # client, Atlas, Tower
pip install "overwing[agents]"      # OpenAI Agents SDK guardrails
pip install "overwing[langchain]"   # LangChain guard runnable + callbacks

Get a free API key at overwing.ai (250 evaluations a day), or let your agent sign itself up with one POST to /api/v1/signup. Try it first with no key: paste anything into the console at overwing.ai.

OpenAI Agents SDK guardrails

from agents import Agent, Runner, InputGuardrailTripwireTriggered, OutputGuardrailTripwireTriggered
from overwing.openai_agents import overwing_input_guardrail, overwing_output_guardrail

agent = Agent(
    name="Support",
    instructions="Help the customer.",
    input_guardrails=[overwing_input_guardrail()],     # scores the user's message
    output_guardrails=[overwing_output_guardrail()],   # scores the agent's final answer
)

try:
    result = await Runner.run(agent, "Reach me at dana@example.com to sort out the refund.")
except (InputGuardrailTripwireTriggered, OutputGuardrailTripwireTriggered) as exc:
    evaluation = exc.guardrail_result.output.output_info["evaluation"]
    print(evaluation.verdict, evaluation.failed_rules)   # "fail" ["pii_detected"]

Both accept rule_set, trip_on="fail" | "fail-or-review", metadata, on_verdict, and fail_open. Input guardrails run in parallel with the agent by default; pass run_in_parallel=False to block before the model is called. Reads OVERWING_API_KEY from the environment, or pass client=AsyncOverwing(api_key=...).

LangChain

Pipe a guard after your model. It scores the answer and acts on the verdict before anything downstream sees it.

from overwing.langchain import overwing_guard, OverwingGuardrailError

chain = prompt | llm | overwing_guard(on_fail="replace")   # or on_fail="raise" (default) / "annotate"
msg = chain.invoke({"question": "..."})
msg.response_metadata["overwing"]   # {"verdict": "pass", "confidence": 0.97, "failed_rules": [], ...}

Or observe every LLM call with a callback handler, which aborts the run on fail:

from overwing.langchain import OverwingCallbackHandler

handler = OverwingCallbackHandler(check_input=True)   # also scores the user's prompt
llm.invoke("...", config={"callbacks": [handler]})
handler.verdicts   # [("input", Evaluation), ("output", Evaluation), ...]

Both accept rule_set, metadata, on_verdict, and fail_open. There is an AsyncOverwingCallbackHandler too.

Atlas: who is this user agent? (no key needed)

Overwing Atlas is a registry of AI crawlers, fetchers and browser agents. Give it a User-Agent string and it says what the string claims to be and whether that claim can be trusted.

from overwing import Atlas

atlas = Atlas()   # no key: 10 lookups a day. With OVERWING_API_KEY set: 100, or your Atlas plan's limit.

who = atlas.lookup(request.headers.get("user-agent", ""))
who.identified       # True
who.agent            # "GPTBot"
who.operator         # "OpenAI"
who.purpose_class    # "Training / bulk crawl"
who.verification     # "User-agent string only (spoofable)"
who.signed           # False: the claim is only a string, so treat it as unverified
who.remaining_today  # 9

Read verification before you act on the claim. who.signed is true only when the operator signs its requests with Web Bot Auth, which you can check. When the allowance is spent, lookup raises OverwingError with status == 429 and retry_after_seconds.

atlas.agents(purpose=..., operator=..., verification=..., q=..., limit=...) searches the registry and atlas.summary() returns traffic shares and field-scan headlines. AsyncAtlas is the async twin. With an API key, Overwing().atlas_lookup(...) does the same lookup.

Tower: let an agent operate a legacy system

Overwing Tower sits between an agent and a system of record. The agent calls typed operations. Tower rules on each one: execute it, ask a person, or reject it. Every step gets a signed receipt.

There are two keys. The organization key sets things up. Each agent key is scoped to the operations that agent may call.

from overwing import Overwing, Tower

# Once, as the organization
ow = Overwing()                                   # OVERWING_API_KEY
ow.tower_load_template()                          # starter workflow: email PO to order entry (mock IBM i)
agent = ow.tower_create_agent("order-intake", ["create_order", "cancel_order"])
agent.key                                         # ow_agent_... shown once: store it as OVERWING_AGENT_KEY

# Then, as the agent
tower = Tower()                                   # OVERWING_AGENT_KEY
tower.capabilities()["operations"]                # what you may call, with JSON Schema inputs

action = tower.submit("create_order", order, idempotency_key=email.message_id)

if action.executed:
    action.result                                 # what the system returned
elif action.pending:
    action = tower.wait_for_review(action.action_id)   # a person must approve; do not resubmit
elif action.rejected:
    action.decision.reason                        # why; do not retry unchanged

submit returns for every ruling and raises only when the request itself is wrong. Those errors are typed for agents: e.code (invalid_input, forbidden_scope, quota_exceeded, ...), e.field, e.retryable, and e.suggested_fix.

Use a stable idempotency_key per business request. Repeating it returns the original outcome, with action.replayed set, instead of acting twice.

Also on the agent client: decide (a ruling with no side effects), submit(..., dry_run=True), get, compensate (undo an executed action), get_receipt, verify_receipts and public_key. On the organization client: tower_list_agents, tower_revoke_agent, and tower_agent, which creates an agent and returns a ready Tower. AsyncTower and AsyncOverwing mirror all of it.

Client

from overwing import Overwing, AsyncOverwing

ow = Overwing()   # or Overwing(api_key="ow_live_...")

e = ow.evaluate("Reach me at dana@example.com to sort out the refund.")
e.verdict              # "fail"
e.recommended_action   # "redact": remove the contact details, the message itself is fine
e.failed_rules         # ["pii_detected"]

# Give the rules context and use the context-aware prebuilt set
ok = ow.evaluate(
    "Reach me at dana@example.com to sort out the refund.",
    rule_set="outbound-message",
    context={"recipient": "one known customer", "channel": "email", "owns_contact_info": True},
)
ok.verdict             # "pass": the details are the sender's own, deliberately shared
e.results[1]         # RuleResult(rule="pii_detected", answer=True, confidence=0.98, verdict="fail", ...)

batch = ow.evaluate_batch([{"id": "a", "input": "..."}, {"id": "b", "input": "..."}])
ow.create_rule_set(name="Support tone", slug="support-tone", rules=[...])
ow.usage()

async with AsyncOverwing() as aow:
    e = await aow.evaluate("...")

OverwingError carries status and retry_after_seconds, plus code, field, retryable and suggested_fix when the API supplies them. 429s with a short Retry-After and 5xx are retried automatically. Pass idempotency_key= to make retries safe. Python 3.10+.

How verdicts work

Each rule has a fail condition, an optional review threshold, and a weight. The prebuilt content-safety set checks toxicity, personal data, self-harm, sexual content, and severity. fail means a rule matched. review means a rule was unsure. pass is everything else. Full guide: overwing.ai/llms.txt. Reference: overwing.ai/docs.

Also from Overwing

  • overwing on npm: the same client, a Vercel AI SDK middleware, and Agents SDK guardrails for JavaScript.
  • overwing-mcp: the guardrails as MCP tools for Claude, Cursor, and any MCP client.

MIT © Overwing. Verdicts are produced by TypeSafe's Jev System One model; Overwing is not affiliated with TypeSafe.

Metadata

Release files for overwing 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for overwing 0.3.0
File Size Uploaded
overwing-0.3.0.tar.gz 202.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for overwing 0.3.0
File Interpreter ABI Platform
overwing-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 224.8 kB

Release files / overwing-0.3.0.tar.gz

Download URL overwing-0.3.0.tar.gz
Size 202.5 kB
Tags Source
SHA-256 checksum
How to use checksums
0ec753906d6aa0d5d938fdf0852847773d300ee84b3df63d5b2348c4c524910f
BLAKE2b-256 checksum
How to use checksums
77667509b0d5df2b9340553697e560668f688e121b55693e516f903d78eb4825
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / overwing-0.3.0-py3-none-any.whl

Download URL overwing-0.3.0-py3-none-any.whl
Size 22.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dbe86c32063fd102fe7a927143fe565584d6359ef819c6c135e7c0745a054b31
BLAKE2b-256 checksum
How to use checksums
ec8c553767890d9081aeaaf7149b5f47b9bf594f99569e96699c22ad32e952a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release history Release notifications | RSS feed

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page