powforge
Your CrewAI / LangChain / AutoGen tool gets called a thousand times an hour by anonymous agents burning your OpenAI credits. Charge each call 21 sats. One decorator.
pip install powforge
Lightning payment middleware for Python agent tools. You wrote a CrewAI / AutoGen / LangChain tool. Someone is going to call it a thousand times an hour, burn your OpenAI credits, and walk away. You want the call to cost them 21 sats so they only run it when they actually need the answer.
from powforge.l402 import wrap_with_l402
async def query_market(symbol: str) -> dict:
# your real tool here
return {"symbol": symbol, "price": 100_000}
gated = wrap_with_l402(
query_market,
lnbits_url="https://lnbits.example",
lnbits_api_key="invoice-or-admin-key",
sats_amount=21,
)
# First call — no payment proof yet.
unpaid = await gated("BTC")
# {'error': 'payment_required', 'invoice': 'lnbc210n1...', 'payment_hash': '...', 'sats': 21, 'next_step': '...'}
# Pay the bolt11. Then call again with the payment_hash.
paid = await gated("BTC", "payment-hash-from-above")
# {'symbol': 'BTC', 'price': 100000}
That's it. Your tool now charges 21 sats per call.
Why
LLM agents are economic actors. They will retry, fan out, and brute-force any free tool you expose. A 21-sat Lightning gate makes runaway loops self-limiting: the bill grows linearly with calls, and the agent's wallet caps the blast radius before your wallet does.
Install
pip install powforge
Python 3.9+. The only runtime dependency is httpx for async HTTP.
API
wrap_with_l402(fn, **cfg)
Wraps an async (or sync) callable. Returns:
async def wrapped(raw_input, payment_proof: str | None = None) -> Any
Two calling conventions — agent frameworks vary in whether they let you pass two args to a tool callback. Both work:
# Two-arg form
result = await gated("BTC", "payment-hash")
# Envelope form — for single-arg frameworks (CrewAI Tool, LangChain Python)
envelope = json.dumps({
"__payment_proof__": "payment-hash",
"__tool_input__": "BTC",
})
result = await gated(envelope)
Config:
| arg | required | default | notes |
|---|---|---|---|
lnbits_url |
yes* | — | LNBits instance base URL |
lnbits_api_key |
yes* | — | Invoice key (read scope sufficient) |
sats_amount |
no | 10 |
Price per call |
ttl_seconds |
no | 600 |
Paid-cache TTL. None = forever |
memo |
no | "powforge-l402" |
Invoice memo |
state |
no | fresh | Share a PaymentState across wrappers |
* unless you inject create_invoice_fn + check_paid_fn directly
(useful for tests or non-LNBits backends).
create_l402_tool(name=..., description=..., func=..., **cfg)
Returns a {"name", "description", "func"} dict shaped for direct
registration as a CrewAI Tool / AutoGen function tool / LangChain
DynamicTool's Python equivalents. The func is the L402-gated async
callable; the calling framework awaits it.
Payment flow
- Caller invokes the wrapped function with no
payment_proof. - Wrapper mints a Lightning invoice via
POST /api/v1/payments. - Wrapper returns a 402-style dict:
{ "error": "payment_required", "invoice": "lnbc210n1...", "payment_hash": "...", "sats": 21, "next_step": "Pay the invoice, then re-call with the payment_hash as payment_proof." }
- Caller pays the bolt11 with any Lightning wallet.
- Caller re-invokes with the
payment_hashas proof. - Wrapper verifies via
GET /api/v1/payments/<hash>, caches the result forttl_seconds, and runs the wrapped function.
The hash is the receipt. In the canonical L402 macaroon spec the proof is the 32-byte preimage; this package accepts the simpler hash form because LNBits' read endpoint takes the hash, and the wrapper still verifies it against LNBits before unlocking the call. Callers who need cryptographic preimage proof should use the macaroon-flavored L402 gates instead.
Family
This package is the Python sibling of the npm packages:
@powforge/langchain-l402-middleware— LangChain.js@powforge/semantic-kernel-l402— Semantic Kernel JS@powforge/mcp-tool-l402— MCP per-tool wrapper@powforge/mcp-l402-gate— full macaroon flow@powforge/paymcp-l402-provider— paymcp BasePaymentProvider
Same envelope shape across all of them.
License
MIT.
Metadata
Release files for powforge 0.1.2
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 | |
|---|---|---|---|---|
| powforge-0.1.2.tar.gz | 12.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| powforge-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.7 kB
Release files / powforge-0.1.2.tar.gz
| Download URL | powforge-0.1.2.tar.gz |
|---|---|
| Size | 12.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
43b2be13185113739b3c2d49389f82e7da70f3534efef587111f924a38e56473
|
|
BLAKE2b-256 checksum How to use checksums |
0da3ef324d973796e4ab2508af05f74aa4b1b281ec5efa31b98b5bacde629779
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / powforge-0.1.2-py3-none-any.whl
| Download URL | powforge-0.1.2-py3-none-any.whl |
|---|---|
| Size | 10.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c19b8b100da85baebacd6735e235daa0aef7f4d3e1aa89694df2426d6314d29f
|
|
BLAKE2b-256 checksum How to use checksums |
8017552dbb644c50d1a77e9db3b5d61b787f7340cbb2602f27f6440f21310ce6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Security for powforge 0.1.2
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.