Metadata-Version: 2.5
Name: aegis-smart-accounts
Version: 0.2.0
Summary: Python SDK and resumable onboarding CLI for Aegis Smart Accounts
License: MIT
Requires-Python: >=3.10
Requires-Dist: eth-abi>=5.1
Requires-Dist: eth-account>=0.13
Requires-Dist: requests>=2.31
Requires-Dist: web3>=7.0
Description-Content-Type: text/markdown

# Aegis Python SDK

The runtime-check, typed lifecycle, and local explanation APIs documented here
require SDK `0.2.0` or newer. Verify the installed package with
`python -c "import aegis_sdk; print(aegis_sdk.__version__)"`; before `0.2.0` is
published, install this repository checkout for implementation testing.

The released SDK is published as [`aegis-smart-accounts`](https://pypi.org/project/aegis-smart-accounts/).
It requires Python 3.10 or newer. Install it in an isolated environment:

```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install aegis-smart-accounts
```

For repository development instead, use `python -m pip install -e sdk/python`.

`aegis init` records only public identifiers and addresses in a mode-0600 state
file so an interrupted setup can resume. Before its first write it records an
operation marker, which lets a retry rediscover an agent or policy whose HTTP
response was lost. Account deployment, policy activation, and permission mint
also reconcile their durable transaction records instead of broadcasting a
second nondeterministic resource. Exit code `2` means an on-chain operation is
still pending and the same command/state file should be resumed. `PrivateKeySigner` is a development
adapter that holds its key in the running process; production agents should
use `CallbackSigner` with a wallet, HSM, secret manager, or other signing
service.

```bash
export AEGIS_API_KEY=aegissa_...
aegis init --name my-agent --owner 0x... --signer 0x... \
  --chain-id 11155111 --policy-file /path/to/policy.json
aegis doctor AGENT_UUID --permission-id PERMISSION_UUID --asset native
# Equivalent flag form:
aegis doctor --agent-id AGENT_UUID --permission-id PERMISSION_UUID --asset native
```

The shell command `aegis doctor` is distinct from the MCP tool
`aegis_doctor`; use the latter only through the configured MCP server.
Doctor may use an expiring `AEGIS_RUNTIME_API_KEY` with `agent:read` scope.
Issued runtime credentials use the `aegisrt_` prefix; the SDK rejects a
management-format key placed in that variable, because renaming a key does not
narrow its authority.
Provisioning commands still require the wallet-scoped management key and must
run in a trusted control-plane environment. Legacy `erc8004_` management keys
remain accepted during the migration.

For a bounded, API-key-free policy explanation, use
`explain_action_locally(request, rpc_url=..., capability=...)`. The capability
must explicitly identify the account generation, policy-only mode, bound
EntryPoint/enforcer/resolver addresses, all dependency runtime hashes, and the
normalized smart-account executable profile. Use
`load_local_capability(chain_id, generation=...)` to load this data from the
same generated registry consumed by the backend and MCP package. The SDK
re-reads and pins that tuple at one block before evaluating resolver-derived
calldata. Exact verdicts also require a capability promoted by the repository's
versioned conformance-evidence input; the packaged registry keeps untested
tuples unpromoted. Missing, unpromoted, or mismatched
capability data, resolver/read failures, and unknown generations remain
`policyDecision: "unknown"`; a policy pass never means that funding, target
execution, or the submission route is ready. The local lane never signs or
submits a UserOperation.

The API key is sent in the `X-API-Key` header. `Authorization: Bearer` is for
JWTs, not Aegis API keys. Keep the key in secure runtime storage and do not put
it in an agent prompt or checked-in configuration.

A minimal Sepolia policy example is available in the repository at
[`examples/minimal-sepolia-policy.json`](https://github.com/aegisinfra/aegis/blob/develop/sdk/python/examples/minimal-sepolia-policy.json).
Use an explicit policy file that matches the account and chain you intend to
operate on.

Use `permission_calldata(permission_id, calldata)` to create the exact Aegis
permission envelope. Never select a permission by “newest”; pass the permission
UUID or on-chain bytes32 ID explicitly and run doctor immediately before use.

The authenticated client intentionally exposes only routes registered by the
API. It does not invent `/limits`, `/quota`, or `/usage` endpoints. Use
`RuntimeChecker` and `ChainReader` for authoritative typed on-chain reads of
the account binding, permission, per-asset limits, shared usage, quota, reset
time, EntryPoint state, and bundler capabilities. A configured zero daily or
transaction-count limit is unbounded even though the corresponding on-chain
quota return is zero. Usage is shared across permissions for the same on-chain
agent and asset and resets at the fixed UTC-day boundary anchored by the first
recorded spend.

`build_execute` and `build_execute_batch` encode policy-only account calls.
`sign_userop` uses the EIP-191 encoding expected by the account. The preferred
`SafeUserOperation`/`UserOperationLifecycle` path signs for estimation, forces
a fresh signature after gas fields are returned, and defaults to no submission.
The legacy `estimate_userop` and `submit_userop` helpers remain for compatible
low-level integrations, but emit deprecation warnings because they cannot
prove signature freshness. Both reject an unsigned operation before RPC.
Use `wait_for_userop_receipt` after submission. It reads the mined transaction
hash from the nested `receipt.transactionHash` field and exposes it as
`tx_hash`; the top-level `userOpHash` is not an EVM transaction hash.

The SDK is the execution helper, not a hosted bundler. The safe SDK lane uses a
bundler route; self-submit is not silently inferred from a missing URL. For the
full operator handoff, see the [Aegis Quick Start](../../docs/AGENT_SMART_ACCOUNT_QUICKSTART.md)
and [Agent Golden Path](https://app.projectaegis.ai/docs/agent-golden-path).

The required UserOperation sequence is build → sign → estimate → re-sign with
the returned gas fields → submit. Any changed hashed field requires a fresh
signature.

The CLI exposes that same lifecycle for `aegis.action-request.v1`. Prefer the
normal calls form: provide the exact target, value, target calldata, and
permission ID. The CLI reads the EntryPoint nonce and route fees, wraps the
call exactly once, signs for estimation, and replaces the estimated gas fields
before requiring a fresh submission signature. Advanced callers can still
provide a complete raw UserOperation. The command dry-runs by default and
prints a redacted, correlated result; submission is a separate explicit
command:

```json
{
  "schemaVersion": "aegis.action-request.v1",
  "chainId": 8453,
  "account": "0x1111111111111111111111111111111111111111",
  "permissionId": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "calls": [{
    "target": "0x2222222222222222222222222222222222222222",
    "value": "0",
    "data": "0x"
  }],
  "route": { "mode": "bundler", "bundlerUrlRef": "selected-runtime-route" }
}
```

```bash
aegis action run \
  --env-file /absolute/path/agent.runtime.env \
  --request-file /absolute/path/first-action.json \
  --readiness-report-file /absolute/path/first-action.readiness.json

# Only after reviewing the exact explanation and successful estimate:
aegis action run \
  --env-file /absolute/path/agent.runtime.env \
  --request-file /absolute/path/first-action.json \
  --execute
```

The optional readiness file is written atomically with owner-only permissions.
It contains no private key or management credential. Its EIP-191 proof binds
the local report to `account.signer()` so the dashboard can detect tampering;
the dashboard still verifies the live signer, current account/permission
binding, freshness, and owner recovery before showing the handoff as ready.

A calls-form request needs no custom UserOperation construction on supported
routes. Routes whose gas estimator merely echoes supplied limits remain
fail-closed and require promoted measured limits before this automatic path is
enabled. An exact denial always blocks. Unknown or unpromoted capability
support also blocks before signing; the deliberately named
`--unsafe-allow-unknown` option is for expert beta diagnostics and cannot
override a denial. No capability should be promoted until its checked-in live
conformance evidence passes the repository release gate.

Advanced programmatic dry-run-first execution shape:

```python
from aegis_sdk import PrivateKeySigner, SafeUserOperation, build_execute

call_data = build_execute(TARGET, 0, TARGET_CALLDATA, PERMISSION_ID)
userop = {
    "sender": SMART_ACCOUNT,
    "nonce": "0x0",                 # resolve the real nonce first
    "initCode": "0x",
    "callData": call_data,
    "callGasLimit": "0x0",
    "verificationGasLimit": "0x0",
    "preVerificationGas": "0x0",
    "maxFeePerGas": MAX_FEE,
    "maxPriorityFeePerGas": MAX_PRIORITY_FEE,
    "paymasterAndData": "0x",
}

# dry_run signs only for estimation and never submits.
operation = SafeUserOperation.from_userop(userop, ENTRYPOINT, CHAIN_ID)
operation.dry_run(PrivateKeySigner(BOT_PRIVATE_KEY), BUNDLER_URL)

# Submission is a separate, explicit decision after reviewing the dry run.
userop_hash = operation.submit(PrivateKeySigner(BOT_PRIVATE_KEY), BUNDLER_URL, execute=True)
receipt = operation.lifecycle.wait_for_receipt(BUNDLER_URL, timeout=180)
```

`CallbackSigner(address, callback)` passes the 32-byte ERC-4337
UserOperation hash to `callback`; the callback must return the account's
EIP-191/personal-sign signature. Its `user_presence_required` metadata defaults
to `True`. Set it to `False` only for a non-interactive signer such as an HSM.
`PrivateKeySigner.user_presence_required` is `False` because it signs locally.

## Runtime handoff from the dashboard

The downloaded runtime descriptor is intentionally non-secret. It contains an
explicit `AEGIS_SIGNER_SECRET_FILE` reference but no private key or management
API key. Store the descriptor and the separate signer backup outside the
repository, replace the placeholder with the absolute signer-backup path, and
restrict both files before checking them:

```bash
chmod 600 /absolute/path/agent.runtime.env /absolute/path/signer-backup.env
# Edit agent.runtime.env so AEGIS_SIGNER_SECRET_FILE points to signer-backup.env.
AEGIS_BUNDLER_URL='https://your-secret-managed-bundler-route' \
  aegis runtime check --env-file /absolute/path/agent.runtime.env --json
```

The selected `--env-file` remains authoritative for chain, agent, account,
permission, and route identity. The explicit signer file contributes only a
supported signer key or signer endpoint; public address lines are ignored and
backend credential fields are rejected. The checker never scans a directory or
loads another env file, never prints the signer path or secret, and performs
read-only RPC/bundler probes only. Account, EntryPoint, enforcer, and resolver
addresses and runtime code hashes from the dashboard descriptor are compared
with live reads pinned to one block; a mismatch fails readiness rather than
silently substituting the current deployment. A relative signer path is resolved only
relative to the selected runtime descriptor; use an absolute path for clarity.

`build_execute` only wraps already-encoded target calldata with the Aegis
policy envelope. It does not encode a Uniswap, Aerodrome, or other DEX call;
construct that calldata from the exact router ABI for the target chain, then
run Aegis preflight and target-level gas estimation before submission.

When checking an intended token, pass `--asset <address>` (or `native`) to
Doctor. Doctor's normal asset rows describe the permission's configured asset
list; an account holding a token does not by itself mean that token is allowed
by the permission.

Robinhood Chain Testnet (`46630`) metadata is available through
`get_chain_profile(46630)` and its SDK profile is marked `pending`. The v15
contracts are deployed and verified, but Aegis API/provisioning support for this
chain is not enabled for normal onboarding yet, so do not target it through the
API. The SDK deliberately does not publish placeholder contract or test-token
addresses.
