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
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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 redlynr-0.1.1.tar.gz.
File metadata
- Download URL: redlynr-0.1.1.tar.gz
- Upload date:
- Size: 22.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2036d39699dc284fb73a91c2207a412e755dab3be1480f5e8539114a524cf04
|
|
| MD5 |
aa25c1b0ee744f3ea3ba1b29d079982d
|
|
| BLAKE2b-256 |
0f781a67b60a2a4e62e4dc50e6b2b89c44ac6dcc5b2f89ac917dc828dc26abd8
|
File details
Details for the file redlynr-0.1.1-py3-none-any.whl.
File metadata
- Download URL: redlynr-0.1.1-py3-none-any.whl
- Upload date:
- Size: 15.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1b5a1d6d96316ec6daaafacf631b226c7b5f5aa4c23b5910bda4ffccde5e4d7
|
|
| MD5 |
b56291901dd0684700b8a2c19634804a
|
|
| BLAKE2b-256 |
57032261e830dbea7f83444e8e7594d665c3120560d06ff777aa886f892926b2
|