Pre-execution policy and a decision ledger for AI-initiated economic actions
Project description
Valto
Decision infrastructure for AI-initiated economic actions.
AI workflows and agents are starting to call paid APIs, use wallets, place trades, trigger cloud jobs, buy data, and commit budget. Payment rails can answer “can this transaction happen?” Valto answers the more important question:
“Should this AI system take this economic action right now?”
Valto sits before execution. It returns a verdict, records the decision, and lets teams learn from the outcome.
AI workflow / agent
│
│ propose economic action
▼
Valto
│
│ approve / deny / modify / require approval
▼
your existing rail, API, wallet, broker, or tool
│
│ report result + optional usefulness
▼
decision ledger
Valto never holds funds and never moves money. Your application still executes approved actions on its own rail with its own keys.
What Valto gives you
- Observe every proposed AI-initiated spend or economic action.
- Guard actions with budgets, caps, allowlists, duplicate checks, and approvals.
- Explain why an action was approved, denied, modified, or escalated.
- Learn which actions were useful, wasteful, risky, or duplicated.
- Tune policy with evidence instead of vibes.
The core loop is simple:
decide → execute on your rail → report
Only decide and report are Valto calls. Execution stays in your app.
Install
pip install "valto[server]"
valto init
valto serve
This starts a local Valto decision engine at:
http://localhost:4100
It loads ./policy.yaml and writes decisions to ./valto_ledger.db.
First verdict
from valto import Valto
valto = Valto(actor="demo-workflow")
decision = valto.decide(
action="buy_dataset",
amount=4.99,
currency="USD",
payee="api.dataprovider.com",
intent="Need Q2 pricing data for a user report",
)
print(decision.verdict)
print(decision.reason)
Example response:
approve
Within budget; no policy rule triggered.
Run the same request again and the starter policy can deny the duplicate:
deny
Identical data was already purchased recently. Reuse the existing result.
Wire Valto into your app
Valto should sit at the one place economic actions already pass through: your payment helper, tool executor, x402 client, broker wrapper, paid API wrapper, or cloud-job launcher.
from valto import Valto
valto = Valto(actor="research-agent")
def buy_data(payee: str, amount: float, query: str):
decision = valto.decide(
action="buy_data",
amount=amount,
currency="USD",
payee=payee,
intent=f"Buy data for query: {query}",
context={"query": query},
)
if decision.verdict == "deny":
return {"error": decision.reason}
if decision.verdict == "modify":
return {
"error": decision.reason,
"suggested_action": decision.modified,
}
if decision.verdict == "require_approval":
return {"error": "Human approval required", "reason": decision.reason}
# Valto approved. Your code still executes the action.
receipt = execute_on_your_existing_rail(payee=payee, amount=amount)
valto.report(
decision.id,
executed=True,
receipt_id=receipt.id,
result_summary="Dataset purchased successfully",
)
return receipt
Workflows and agents both use the same primitive
Valto is not only for autonomous agents. It works anywhere software is about to commit money, budget, or economic risk.
Deterministic workflow
new lead → score lead → buy enrichment if score > 80 → update CRM
Valto is called at the known paid step.
decision = valto.decide(
actor="lead-enrichment-workflow",
action="buy_enrichment",
amount=0.25,
payee="people-data-api.com",
context={"lead_score": 91},
)
Agent
research agent decides it needs paid market data
Valto is called when the agent proposes the economic action.
decision = valto.decide(
actor="research-agent",
action="buy_market_report",
amount=2.00,
payee="market-data-api.com",
intent="Improve competitive analysis for the user's report",
context={
"task": "compare agent payment startups",
"alternatives_considered": ["free search", "cached data"],
},
)
Same interface. Different autonomy level.
Policy
Policies are YAML. They define budgets and ordered rules.
budgets:
per_action_max: 25.00
daily_max: 100.00
by_category:
data: { daily_max: 20.00 }
categories:
buy_dataset: data
buy_enrichment: data
rules:
- id: duplicate_data
verdict: deny
reason: "Equivalent data was already purchased recently. Reuse it."
match:
actions: [buy_dataset, buy_enrichment]
duplicate_within_hours: 24
- id: expensive_action
verdict: require_approval
reason: "Actions over $50 require human approval."
match:
amount_gt: 50
default: approve
Every decision records the policy version that produced it.
Outcomes
Execution and usefulness are different.
A payment may execute successfully but still be wasteful. Valto records both.
valto.report(
decision.id,
executed=True,
receipt_id="tx_123",
result_summary="API returned 42 rows",
)
Later, once the result is knowable:
valto.evaluate(
decision.id,
useful=True,
score=0.8,
note="The data was used in the final report",
)
Outcome labels turn the decision ledger into policy-tuning data.
API surface
| Endpoint | Purpose |
|---|---|
POST /v1/decide |
Proposed economic action in, verdict out |
POST /v1/outcomes |
Report what happened after execution |
POST /v1/outcomes/{id}/usefulness |
Deferred usefulness label |
GET /v1/decisions |
Decision ledger |
GET /v1/policy |
Current policy and version |
PUT /v1/policy |
Replace policy |
What Valto is not
Valto is not a wallet. Valto is not a payment processor. Valto is not a broker. Valto is not a prompt. Valto is not an agent framework.
Valto is the decision layer between AI systems and economic actions.
Why not just use a system prompt?
Prompts are advice. Valto is enforcement.
A prompt can tell an agent not to overspend. Valto can deny the spend before it executes, record the decision, and preserve budget state across sessions.
Use both:
Prompt: teaches the agent to ask before spending.
Valto: makes the rule real.
Benchmark
This repo includes a vending-business simulation used to measure AI economic behavior with and without Valto. See benchmark/README.md and RUNNING.md for the full experiment protocol.
Project details
Release history Release notifications | RSS feed
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 valto-0.1.0.tar.gz.
File metadata
- Download URL: valto-0.1.0.tar.gz
- Upload date:
- Size: 23.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9e1e9c330cc4003308bfca48e8c16fad0e8a008ad8364ce1837a4ad2c031dde
|
|
| MD5 |
011c4ea034d4f0540d975dbe534372da
|
|
| BLAKE2b-256 |
6fd2176edc2a1c9b527e33b8d5e2932d6f3b07768a75751cdc7404c42a417cfd
|
File details
Details for the file valto-0.1.0-py3-none-any.whl.
File metadata
- Download URL: valto-0.1.0-py3-none-any.whl
- Upload date:
- Size: 28.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df09b631c87d78068cb3948d42a1d883d21e7cd081da8ca13550371998eb22eb
|
|
| MD5 |
6451ca05aef666fda17cf5d5276f4b68
|
|
| BLAKE2b-256 |
ebb86d3f9d80de1b87e21e7ebf7e0a8dc0a53075e54c8a188030b67f3ed7f6ef
|