> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alterscope.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Build an autonomous treasury agent

> Compose alerts, scoring, and a decision policy. Execution stays with you.

You operate a DAO treasury and want an agent that reallocates idle stablecoins toward the best risk-adjusted yield, subject to mandate constraints. Alterscope provides the data and the signals; the agent makes the call; your existing executor signs the transaction.

<Warning>
  Alterscope does not execute transactions on your behalf. This recipe ends at the decision; the actual write to chain is your codebase.
</Warning>

## What you build

A loop that, on each tick or on each `vault.cap.changed` event:

1. Pulls the candidate opportunity universe.
2. Scores each candidate against the current portfolio.
3. Picks the top reallocation that satisfies your mandate.
4. Emits a signed proposal to your executor.

## 1. Discover candidates

```python theme={null}
from alterscope import AlterscopeClient

client = AlterscopeClient(api_key="sk_live_...")

candidates = client.yield_opportunities.list(
    asset=["USDC", "USDT", "DAI"],
    chain=["ethereum", "base", "arbitrum"],
    risk_band=[1, 2],
    min_tvl_usd=10_000_000,
    sort_by="net_apy",
    order="desc",
    limit=25,
)
```

## 2. Score each candidate against the current book

```python theme={null}
current = load_treasury_positions()

best = None
best_delta = 0
for c in candidates.data:
    proposed = current + [{"opportunity_id": c.id, "notional_usd": 1_000_000}]
    analysis = client.portfolio.analyze(positions=proposed, include_scenarios=True)
    if analysis.risk.band > 2:
        continue
    delta = analysis.expected_apy_net - current_apy_net
    if delta > best_delta:
        best_delta = delta
        best = (c, analysis)
```

## 3. Apply mandate constraints

Encode your policy as code, not as prose. Common constraints:

* Per-protocol cap: no more than 30% of treasury in a single protocol.
* Oracle-provider cap: no more than 50% of treasury behind a single oracle provider.
* Reject any candidate whose `meta._agentic.freshness.status` is not `fresh`.
* Reject any candidate whose `risk.dominant_factors[0]` is `oracle.stale_risk` or `peg.deviation`.

```python theme={null}
def passes_mandate(candidate, analysis, current) -> bool:
    if analysis.meta._agentic.freshness.status != "fresh":
        return False
    if analysis.risk.dominant_factors[0].name in ("oracle.stale_risk", "peg.deviation"):
        return False
    return concentration_ok(current, candidate)
```

## 4. Emit a signed proposal

```python theme={null}
if best and passes_mandate(*best, current):
    candidate, analysis = best
    proposal = sign_proposal({
        "from": "treasury_idle_usdc",
        "to": candidate.id,
        "notional_usd": 1_000_000,
        "expected_apy_net": analysis.expected_apy_net,
        "rationale": analysis.risk.dominant_factors,
        "as_of_block": analysis.meta._agentic.freshness.as_of_block,
    })
    submit_to_executor(proposal)
```

## 5. Audit trail

Log every decision, including the ones that were rejected and why. The `request_id` in `meta.request_id` ties the proposal to the exact API responses that produced it.

## 6. Tier requirements

Factor attribution and stress scenarios require the Analyst tier or higher (the `read:yield:detail` scope). WebSocket triggers (a tighter feedback loop than polling) also require the Analyst tier or higher. Custom factors and per-route uplift require Enterprise.
