redlynr-python
Python SDK for Redlynr — the agent guardrail decision engine.
Detection isn't enforcement. Redlynr identifies when an agent should stop. This SDK makes sure it does.
Installation
pip install redlynr
Zero external dependencies for trial token usage. For x402 payment support, install:
pip install redlynr requests "x402[evm]" eth_account
Quickstart
1. Register your tenant (one-time)
from redlynr import RedlynrClient
owner_token = RedlynrClient.register(
base_url="https://redlynr.com",
tenant_id="my-agent-prod",
)
# Store owner_token securely — it is never shown again.
2. Create a client
client = RedlynrClient(
base_url="https://redlynr.com",
tenant_id="my-agent-prod",
owner_token=owner_token,
chain_id="chain-001",
)
3. Guard every tool call
from redlynr import RedlynrBlocked, RedlynrSlowDown
try:
result = client.guard(my_tool_fn, {"query": "..."}, step_cost=0.01)
except RedlynrBlocked as e:
print(f"Stopped: {e.reason}") # tool was NOT called
except RedlynrSlowDown as e:
print(f"Slow down: wait {e.wait_seconds}s") # only if raise_on_slow_down=True
When Redlynr says stop, guard() raises RedlynrBlocked and the tool function is never called. When Redlynr says proceed or slow_down (default), guard() calls the tool and returns its result.
Authentication
Redlynr supports two authentication modes for /run calls.
Trial token (free tier)
Obtain a PoW trial token for 30 free calls:
import hashlib, json, urllib.request
def get_trial_token(base_url="https://redlynr.com"):
with urllib.request.urlopen(f"{base_url}/trial/challenge") as r:
ch = json.loads(r.read())
nonce, difficulty = ch["nonce"], ch["difficulty"]
prefix = "0" * difficulty
counter = 0
while not hashlib.sha256(f"{nonce}{counter}".encode()).hexdigest().startswith(prefix):
counter += 1
data = json.dumps({"nonce": nonce, "solution": str(counter)}).encode()
req = urllib.request.Request(
f"{base_url}/trial/claim", data=data,
headers={"Content-Type": "application/json"}, method="POST"
)
with urllib.request.urlopen(req) as r:
return json.loads(r.read())["trial_token"]
trial_token = get_trial_token()
client = RedlynrClient(
base_url="https://redlynr.com",
tenant_id="my-tenant",
owner_token=owner_token,
chain_id="chain-001",
trial_token=trial_token,
)
x402 payment (paid tier)
For production use, pass an x402-wrapped requests.Session. The session handles USDC payment on Base mainnet automatically on every /run call.
import requests as req_lib
from eth_account import Account
from x402.client import x402ClientSync
from x402.mechanisms.evm.exact import ExactEvmScheme
from x402.http.clients.requests import wrapRequestsWithPayment
# Build x402 session once
account = Account.from_key(os.environ["BUYER_PRIVATE_KEY"])
x402_client = x402ClientSync()
x402_client.register("eip155:8453", ExactEvmScheme(signer=account))
session = wrapRequestsWithPayment(req_lib.Session(), x402_client)
client = RedlynrClient(
base_url="https://redlynr.com",
tenant_id="my-tenant",
owner_token=owner_token,
chain_id="chain-001",
session=session, # x402 payments handled automatically
)
When session is provided it is used for all /run calls. All other endpoints (/register, /policy, /audit, /reset, /pause) use plain urllib and are unpriced.
RedlynrClient reference
RedlynrClient(
base_url, # str — Redlynr service URL
tenant_id, # str — your registered tenant namespace
owner_token, # str — token from /register
chain_id, # str — unique ID for this agent chain
agent_id="orchestrator", # str — identifier for this agent
depth=0, # int — nesting level (0=top, 1=sub-agent, ...)
chain_type=None, # str|None — "interactive", "batch", "scheduled", or None (auto)
cost_fn=None, # callable(tool_name, args) -> float — auto cost resolution
raise_on_slow_down=False, # bool — raise RedlynrSlowDown instead of transparent wait
trial_token=None, # str|None — PoW trial token for free tier
session=None, # requests.Session|None — x402-wrapped session for paid tier
)
One client per chain. Each RedlynrClient owns state for exactly one chain_id. For multi-agent systems, each agent instantiates its own client with the same chain_id and tenant_id but a distinct agent_id and appropriate depth.
chain_type — declare explicitly
If chain_type is not declared, Redlynr auto-detects the chain type from call patterns and may promote to "batch" after 5 consecutive novel-target calls. Batch chains have a default step limit of 100. Always declare chain_type="interactive" explicitly when you want tight step caps to fire:
client = RedlynrClient(
...
chain_type="interactive", # pins limits for the chain's lifetime
)
guard()
result = client.guard(fn, args, *, tool_name=None, step_cost=None)
The main enforcement primitive. Calls /run before executing fn. Enforces the decision:
| Decision | Behavior |
|---|---|
proceed |
fn(**args) is called, result returned |
slow_down |
Waits wait_seconds if set, then calls fn. If raise_on_slow_down=True, raises RedlynrSlowDown instead |
stop |
Raises RedlynrBlocked. fn is never called |
Chain state (step count, retry detection, tool fixation, novelty) is tracked automatically in-process with no external dependencies.
args are passed to fn as keyword arguments:
def search(query: str, limit: int = 10):
...
result = client.guard(search, {"query": "...", "limit": 5}, step_cost=0.01)
# SDK calls: search(query="...", limit=5)
Policy
Set guardrail limits for your tenant:
client.set_policy(policy={
"steps_retries": {
"max_steps_per_chain": 20,
"max_retries": 2,
"warn_at_steps_pct": 75,
},
"cost": {
"max_spend_per_period": 1.00,
"period_seconds": 86400,
},
})
Or apply a named template:
client.set_policy(template="interactive_agent")
# Available: "interactive_agent", "batch_pipeline", "autonomous_researcher"
Default policy limits
| Limit | Interactive | Batch |
|---|---|---|
max_steps_per_chain |
20 | 100 |
max_retries |
2 | 2 |
max_depth |
5 | 5 |
max_spend_per_chain |
$0.30 | $2.00 |
warn_at_steps_pct |
75% | 75% |
Multi-agent usage
# Orchestrator (depth=0)
orchestrator = RedlynrClient(
base_url="https://redlynr.com",
tenant_id="my-tenant",
owner_token=owner_token,
chain_id="chain-001",
agent_id="orchestrator",
depth=0,
chain_type="interactive",
session=session,
)
# Sub-agent (depth=1) — same chain_id and tenant_id
researcher = RedlynrClient(
base_url="https://redlynr.com",
tenant_id="my-tenant",
owner_token=owner_token,
chain_id="chain-001",
agent_id="researcher",
depth=1,
chain_type="interactive",
session=session,
)
Both agents call guard() before every tool execution. Step counters are shared server-side by chain_id. The chain stops when either agent exceeds the limit.
Exception reference
from redlynr import RedlynrBlocked, RedlynrSlowDown, RedlynrError
| Exception | When raised | Key attributes |
|---|---|---|
RedlynrBlocked |
Redlynr returns stop |
reason, response |
RedlynrSlowDown |
Redlynr returns slow_down and raise_on_slow_down=True |
reason, wait_seconds, response |
RedlynrError |
API or connection error | message |
Stop reasons
retries_exhausted, step_cap_exceeded, cost_budget_exceeded, chain_cost_exceeded,
chain_depth_exceeded, repetition_detected, tool_fixation_detected,
volume_pressure_blocked, agent_paused, lock_contention
Other methods
client.reset() # clear this chain's step counter server-side
client.audit() # last 100 /run decisions for this tenant
client.audit_analyze(min_chains=3) # advisory threshold suggestions
client.pause(agent_id=None, paused=True) # pause or unpause an agent
client.health() # service health check
client.run_raw(**kwargs) # raw /run call, bypasses guard() state tracking
Pricing
/runcalls: $0.001 USDC per call (Base mainnet)- All other endpoints (
/register,/policy,/audit,/reset,/pause,/health): free - Free trial: 30
/runcalls per PoW token
Links
- Service: redlynr.com
- PyPI: pypi.org/project/redlynr
- GitHub: github.com/HDGForge-Labs/redlynr-python
- License: MIT
Metadata
Release files for redlynr 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| redlynr-0.1.1.tar.gz | 22.1 kB | Without provenance | Details for redlynr-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| redlynr-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for redlynr-0.1.1-py3-none-any.whl |
Total release size: 37.8 kB
Release files / redlynr-0.1.1.tar.gz
| Download URL | redlynr-0.1.1.tar.gz |
|---|---|
| Size | 22.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e2036d39699dc284fb73a91c2207a412e755dab3be1480f5e8539114a524cf04
|
|
BLAKE2b-256 checksum How to use checksums |
0f781a67b60a2a4e62e4dc50e6b2b89c44ac6dcc5b2f89ac917dc828dc26abd8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / redlynr-0.1.1-py3-none-any.whl
| Download URL | redlynr-0.1.1-py3-none-any.whl |
|---|---|
| Size | 15.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b1b5a1d6d96316ec6daaafacf631b226c7b5f5aa4c23b5910bda4ffccde5e4d7
|
|
BLAKE2b-256 checksum How to use checksums |
57032261e830dbea7f83444e8e7594d665c3120560d06ff777aa886f892926b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for redlynr 0.1.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.