Skip to content

Houndsight-ai/houndsight-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

houndsight

CI PyPI License

The official Python SDK for Houndsight. Houndsight is an agent leash, not just a camera — alongside trace collection, the SDK exposes a synchronous policy gate (trail.leash) that blocks an agent until a remote decision permits the action.

pip install houndsight
import houndsight as hs

hs.init(api_key="sk-hnd-...", agent="sales-pipeline")

with hs.trail(trigger="user_message", payload={"text": "Q2 forecast"}) as t:
    with t.sniff("salesforce_query", layer="execute") as s:
        s.cost(0.0001)
        s.output({"deal_count": 17})
    t.set_output("Posted forecast")

Docs: https://docs.houndsight.ai · Discord: https://discord.gg/houndsight

The leash

Use trail.leash(...) before any action your agent shouldn't take without oversight — sending external email, charging a card, deleting customer data, posting publicly, hitting a destructive API.

decision = trail.leash(
    action_name="stripe.charge",
    action_summary=f"Charge customer ${amount/100}",
    risk_signals={
        "amount_usd": amount / 100,
        "data_categories": ["financial"],
    },
    payload={"customer_id": cust_id, "amount_cents": amount},
    timeout_seconds=600,
)

if not decision.approved:
    log.warning("Leashed: %s. See %s", decision.reason, decision.trace_link)
    return

# Use the reviewer's modifications if any.
payload = decision.modified_payload or original_payload
stripe.Charge.create(**payload)

decision.decision is one of:

value approved meaning
approved True Gate allows the action.
modified True Approved with edits — use decision.modified_payload.
rejected False A human reviewer denied the action.
blocked False A floor rule fired and blocked the action automatically.
timeout False No decision within timeout_seconds, or the gate service was unreachable / returned 5xx.
error False The gate service rejected the request as malformed (4xx). The gate is broken, not the action. Almost always means the SDK and server contracts have drifted; check decision.reason for the response body.
async False Only with blocking=False. Decision pending server-side.

timeout and error are both fail-closed but they mean different things — the dashboard alerts on them differently. timeout is "we tried and the gate didn't answer in time"; error is "we tried and the gate said our request was wrong" (bad API key, bad endpoint URL, schema mismatch).

Calls block by default for up to timeout_seconds. Pass blocking=False to fire-and-forget; check the dashboard at decision.trace_link for the final outcome.

TRUST MODEL — read this before deploying

The SDK enforces nothing locally. leash() POSTs the request to Houndsight, reads the server's decision, and returns it. That's the whole mechanism — there is no local rules engine, no client-side policy file, no "approved actions" allowlist baked into the SDK.

This is deliberate. A tampered SDK cannot bypass the gate because the gate is gated by the presence of the leash() call itself. The only way an agent skips the gate is to skip the call — and that manifests in the trace as the absence of a review-layer step for the corresponding sensitive action.

In other words:

  • leash() is a contract, not a sandbox.
  • Calling leash() and then ignoring decision.approved is a bypass — and it is visible in the trace: there will be an approved=False decision followed by the action's step. The dashboard flags this.
  • Not calling leash() on a sensitive action is also a bypass — and it is visible in the trace by what isn't there: a sensitive-classified step (e.g. stripe.charge) with no preceding review-layer step. The dashboard flags this too.

The audit story relies on the SDK emitting a review-layer AgentStep for every leash() call. The SDK guarantees this even on the failure paths (timeout, network unreachable, server 5xx). Don't catch and swallow exceptions from inside leash() — there aren't any to catch.

Concepts

  • Trails group an agent run end-to-end (hs.trail(trigger=...)).
  • Sniffs record each step's input, output, cost, tokens, and per-call events (t.sniff(name, layer="...")).
  • Leashes block until a remote decision lets the agent proceed (t.leash(...)). See above.
  • Barks attach typed custom events (hs.bark("cache_hit", key=...)).
  • Collars decorate functions for automatic tracing (@hs.collar).

Releases

No releases published

Packages

 
 
 

Contributors

Languages