# Agent Life · Public Agent Skill

> Status: public at https://agentlife.fun/skill.md. Addresses are authoritative at https://agentlife.fun/plaque.config.json; the table below is a deployment snapshot only.
> Companion: product PRD (held by the project). This Skill is for a user's AI Agent to execute on-chain actions.

# Agent Life · Agent execution Skill

Agent Life (ALIFE): hang a Life Card, hand shifts to your Agent—you clock out, it clocks in.
Agent 人生（Agent Life）：代币 ALIFE；挂上人生牌，把班次交给 Agent，你收班它上岗。

For a user's AI Agent to execute on-chain actions from prompts. Authoritative numbers live in the project PRD; this Skill is an execution checklist and iron rules — not a place to rewrite economics.

**Chain**: BSC · **Token**: BEP-20 **ALIFE** · **Public name**: Agent Life / Agent 人生 · **Official X**: [@Agentlifebnb](https://x.com/Agentlifebnb)
**End-game job**: **BOSS** (display name is the word BOSS; the brand stays Agent Life). On-chain job index 0–4 and course bits 1/2/4/8 are unchanged.
**Contract addresses**: use the served `plaque.config.json` (`chainId` **56** + `contracts.*`). The table below is that file. **Vault = 0x0** when the file says so. Convert is disabled — do not call it. Agents **must not invent addresses** and must not send these calls to another chain. `modules` in the config is a hint, not a gate.

**Supply**: total **20,000,000** ALIFE. Mint **5,000,000**. LP **4,000,000**. Game **11,000,000**. There is no airdrop. Do not call `claimAirdrop`, `airdropSigner`, `upgradeToAndCall`, or `proxiableUUID`. Use only the addresses in the served plaque.config.json.

**Public stage**: 当前开放：Mint. Tell users mainnet wall-clock only — regular shift **4h**, overtime **2h**, cooldown **2h**, each lesson **12h**, safety education **2×12h** inside **72h**, shop suspension **72h**. Do not shorten those hours in user-facing text. Do not invent a second chain's addresses. There is **no countdown**. A module is open only when its getter is true. **Before every write, read the getter yourself** (`mint.active()`, `mint.closed()` if the call does not revert, `mint.socialActive()`, `liquidity.added()`, `cardMint.mintOpen()`, `cardMint.PRICE()`, `game.active()` ). If a switch is false, do not submit that action. `liquidity.added()` gates token-pool transfers. It does not gate Life Card `mintCard` or `mintCardFree`, and it does not gate token-pack `mint`. Web Mint follows `mint.active()` (page says **即将开放** when it is off). The Life Card page shows price × count in BNB, circulating, the mint prompt, and an enabled mint button when `cardMint.mintOpen()` is true. While it is false the page shows **即将开放**, payment **???**, and no mint prompt. Pay config `params.lifeCardPriceWei` (0.01 BNB) once mint is open. Harbor work / learn / shop follow Game. The website market stays **即将开放**. Shop stake is **契金 / bond**. Token-pack mint runs to **50,000**. Transfers stay locked until the pool opens. Hard cap in this file is `20000` (chain `HARD_CAP()`, else 20000). Life Card price is **0.01 BNB** (`10000000000000000` wei) via `mintCard`. 

| Module | This deployment · BSC chainId 56 (served `plaque.config.json`) |
|---|---|
| Token (symbol from served `tokenMeta`; display ALIFE) | `0x401667A68672A0B14A059B1a61b7d7181646D515` |
| Life Card NFT | `0x43985869d9CcF008A8BF23b264CEc1395EC9A90c` |
| Mint (token packs, social `claimSocial`) | `0x7B1D61C51484cA8064c7e943282AE3265C98d91a` |
| Liquidity (add pool + unlock transfers) | `0x06F04BCd31CC2B2859c7F718913F42585b753062` |
| TaxVault | `0xF6B795f8fcAF2C35A1F18CE4Af4f134713F97cAb` |
| CardMint (Life Card, `mintCard`) | `0xC85cc41b26a57e212472b5b685675d4425C7F25C` |
| Convert (disabled, do not call) | `0x36CBe731fdD4516B4cF839f6B4294E2B247BC8ef` |
| R1 Vault | `0x0000000000000000000000000000000000000000` (unset in served config — do not invent) |
| Game (proxy) | `0x013FcE620f1BF51920CA1E4ea3cCBa5D9FfAC432` |
| Game (impl) | `0x013FcE620f1BF51920CA1E4ea3cCBa5D9FfAC432` |
| Game (lib) | `0xa8E77e6fa9fF2c499561D688ceC098CCF0647319` |
| Life | `0xc9BBAb309d3Ea5b1A1C8F9763b2A6D5494C1c368` |
| Market | `0x56513F181350dF62B74B0518d99fBe2741257D23` |
| WBNB | `0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c` |
| Router | `0x10ED43C718714eb63d5aA57B78B54704E256024E` |
| `.ai` Agent ID (external gate) | `0x60B9262456dE011F7d15a54CdD8c48bAaa8B022F` |

RPC: served `rpcUrl` (`https://bsc-dataseed.bnbchain.org`); explorer: `https://bscscan.com`. `modules` in that file is a hint, not a gate. A module is open only when its getter on **this** chain (chainId 56) is true. Social tweet / `claimSocial` uses this mint when `socialActive()` is true. Do not send these calls to another chain.

---

## 1. Iron rules

1. **Never invent on-chain outcomes in chat**: events, wage rolls, and reputation are decided by the contracts from the shift seed-block hash (seed block = `beginShift` block + 1). The Agent only builds transactions and explains on-chain results — **it does not decide wins/losses or events**.
2. **Four high-risk actions — confirm with the user every single time** (preset policies do not count): **sell NFT, return the bond (退契金), open a shop, open a branch**. Confirmation must state consequences (burn / lose eligibility / bond lock, etc.).
3. **Invalid Life Card IDs**: `#tokenId` only increases and never fills gaps. Before any Life Card action, `ownerOf(tokenId)` (or `card(tokenId)`) must succeed and the holder must be the user's wallet; on revert / missing → **stop immediately**, tell the user "this Life Card is burned or invalid", and do not retry. **Redeem is cancelled** — there is no Convert.redeem.
4. **Stage not `active`**: contracts will reject; report status only — do not burn gas retrying.
5. **Do not invent contract addresses / ABIs / unit prices**; if unknown, check official config or a read-only dashboard, then stop and ask the user.
6. **One action, one report**: before building a tx, say what you will do, cost, and success criteria; submit after wallet confirm; short report after (on failure: reason + on-chain state).
7. Use story job names (dishwasher / delivery rider / taxi driver / street stall owner / BOSS). L2 is delivery rider; L3 is taxi driver — do not call the taxi job a delivery rider.
8. **Safety education / license risk — never silent（安全教育不可静默）**: After **every** `settleShift` (and **before** the next `beginShift`) for a Life Card that can drive (taxi driver / driving permit unlocked), read `study(tokenId)` / status for `safetyRequired`, `safetyDeadline`, `roadRevoked`, `driverViolations`. If `safetyRequired` just flipped or is true: **must tell the user in that same report in 大白话** — 30 天内违章已满 3 次 → 必须上安全教育；**截止时间换算 Asia/Shanghai**；逾期吊销驾驶证、职业掉回外卖员、驾驶证要重新交学费；当前**不能再开的士**；未开课前可打低职；一旦 `startSafety` 则上课中不能打工. **Must not** keep looping `beginShift` as driver until safety is cleared (or user explicitly accepts that the tx will revert). If `LicenseRevoked` / deadline already passed on touch: report clearly that the driving permit is revoked and restudy needs tuition. There is **no** background push — the Agent must surface this whenever it settles, loops, or is next contacted.

---

## 2. Pre-flight checks (shared)

1. Network = served config `chainId` (**56**). Do not switch the wallet to the other chain. Wallet is the user-named account.
2. Read stage `active`, hard circulating cap, game pool tier \(m\), and daily soft-cap used/limit (when readable).
3. Read balances: BNB, ALIFE, Life Card NFT ids; whether the wallet holds a **bound `.ai` NFT** (`balanceOf(wallet) > 0` on that contract).
4. Same Life Card: work / study / overtime / listing are **mutually exclusive**; multiple Life Cards may run in parallel.
5. Cooldown blocks the next **work** shift, **not** study; unfinished lesson claims block starting the next work shift.

## 2.1 Frontend vs Agent

- **Website can act directly**: while the public Mint page shows **即将开放**, do **not** submit a paid mint or claimSocial. When `mint.active()` is true: **/mint** (connect wallet, send paid `mint` on the served chain). `claimSocial` when `socialActive()` is true, same chain and the served mint. **Life Card mint** (`/plaque`) shows **即将开放**, payment **???**, and hides the mint prompt while `cardMint.mintOpen()` is false. When it is true, the page shows the price and the prompt (default 10 cards, clamped by `remainingMintQuota`) and the mint button sends paid `mintCard`. Do not send paid `mintCard` while `mintOpen` is false. An approved wallet may still send one free pack or one `mintCardFree` when `cardMint.mintOpen()` is true (§3, §4). **NFT market** stays **即将开放** — do not submit list / buy from the site. **Agent Life shop bond return** (`/harbor` 「我的店铺 · 退契金」: two-step `withdrawShop`) stays available when the harbor UI exposes it. **No web redeem** (redeem cancelled). Work / learn / shop follow `game.active()` only. Do not call `stageActive`.
- **Other actions** (work, study, open shop, etc.): site is read-only + prompt; user sends the prompt to an Agent.
- **Eligibility**: contracts enforce; on mismatch they revert — Agent reports truthfully. Burned IDs have no Life Card rights.
- **Binance Agent Wallet — three paths**: (1) Web scan — top-right Connect → Agent Wallet scan binds a session; start txs on /mint or /plaque; user approves in Binance App. (2) Prompt — user pastes the homepage prompts to an Agent that follows this Skill. (3) CLI — Agent installs `npx skills add binance/binance-skills-hub/skills/binance-web3/binance-agentic-wallet` and signs per that Skill. If the wallet has not enabled the target chain, stop and tell the user.

## 2.2 Other agent wallets (OKX Agentic Wallet / MetaMask Agent Wallet)

These are **Agent-side CLI wallets** (keys in TEE / server; Agent never sees them). They **do not inject into the page**, so they are not in the site Connect list (site only connects browser wallets and Binance Agent Wallet scan). The user asks the Agent to run this Skill with them. First confirm chain: `onchainos wallet chains` / `mm chains list` must include the served chainId (**56**). If it is missing, stop and tell the user. Do not switch to another chain. Reads use RPC `eth_call`; writes ABI-encode calldata first (e.g. `cast calldata "mintCard()"` with value 10000000000000000 to `$CARD_MINT`). Do not approve ALIFE for a Life Card.

| Action | OKX (`onchainos`) | MetaMask (`mm`) |
|---|---|---|
| Life Card `mintCard` | `onchainos wallet contract-call --chain <id> --to $CARD_MINT --input-data <mintCard calldata> --amt 10000000000000000` | `mm wallet send-transaction --chain-id <id> --payload '{"to":"$CARD_MINT","data":"<mintCard calldata>","value":"0x2386f26fc10000"}' --intent "Mint one Life Card for 0.01 BNB" --wait` |
| Mint packs (payable) | `--to $MINT --input-data <calldata> --amt <value wei>` | `"value":"0x<hex value>"` |

- Paid Life Card value is exactly `10000000000000000` wei per card. wlNftV2 schema WlNftFreeV2 version 2 chainId 56 cardMint 0xC85cc41b26a57e212472b5b685675d4425C7F25C. Call mintCardFree(uint256 aiTokenId, uint256 nonce, uint256 deadline, bytes signature) only at that address, with claimNonce as nonce. Do not use 0x02dFF2efd261EfdB5e490032849EdcF5116faC28 for that call. `mintCardFree(uint256 deadline, bytes signature)`. Before that call, read the cardMint address and `EIP712_VERSION()`. If the address is `0x02dFF2efd261EfdB5e490032849EdcF5116faC28` or the version is not `2`, use only `mintCardFree(deadline, signature)` and do not pass `aiTokenId` or a nonce. If the version is `2` and the address is not that legacy card mint, `POST /api/wl/auth/nonce`, sign `WlRequest` with EIP-712 (`eth_signTypedData_v4`) or EIP-191, and `POST /api/wl/sign` with that `auth`. `baw sign-message preview --binanceChainId 56 --signType EIP712` takes a full `eth_signTypedData_v4` request whose first param is the agent wallet and whose second param is this WlRequest typed data (`domain` name `Agent Life WL`, version `1`, chainId 56, verifyingContract the `.ai` registry). After the user confirms, `baw sign-message execute --requestId` returns 64-byte `signature` (`r||s`) plus `signatureRecovery` `00` or `01`. Send both fields. A 65-byte injected signature omits `signatureRecovery`. Do not invent a recovery bit from `s`. When `schema` is `WlNftFreeV2`, call `mintCardFree(uint256 aiTokenId, uint256 nonce, uint256 deadline, bytes signature)` once, using `claimNonce` as `nonce` and value 0. If the response is `nft_sign_blocked`, stop. Do not send a V2 signature to the legacy card mint. A transfer of the same `.ai` does not earn a second free card. Token `wlSig` stays `WlTokenFree(address wallet,uint256 aiTokenId,uint256 deadline)`. The V1 call still sends value 0 once. Do not approve ALIFE for a Life Card. Do not call Convert (`0x91bbdcc7` is the disabled `convert()` selector).
- Before send, restate and confirm per §1; each of the four high-risk actions needs its own confirm. If the wallet's simulation / risk check fails, **do not broadcast** — report the error.
- Under MetaMask Guard Mode, unfamiliar contracts may need user 2FA; write a clear `--intent`.

## 2.3 Agent Wallet whitelist calls (not the webpage)

The webpage signs only with an injected browser wallet on BSC at the same address. That signature is 65 bytes and omits `signatureRecovery`. The page does not run `baw` and does not submit an Agent Wallet session as whitelist auth. If the page has no injected account, stop on the page. Do the whitelist API from this Skill instead.

This path is the user's Agent calling the backend. It is not a chain transaction. Do not invent endpoints. Base URL `https://agentlife.fun`.

Three different signatures:

1. **API auth.** The user wallet signs `WlRequest`. Send it only to the whitelist API. Do not pass it to `mint` or `mintCardFree`.
2. **Claim signature.** `POST /api/wl/sign` returns a quota-signer signature. That `signature` is the on-chain argument. It is not `auth.signature`.
3. **On-chain call.** Use the claim signature, the claim `deadline`, and for NFT V2 the `claimNonce`. Those are not the API `nonce` or API `deadline`.

Before `sign`, read the sale getter on chain 56 at the served config address: `mint.active()` for a token signature, `cardMint.mintOpen()` for a Life Card signature. If the read fails or is not true, do not call `sign`. `wl_sign_open` in `GET /api/wl/config` does not open signing. Tasks can still be submitted before the sale. The issue mode (`nft` or `token`) is what records the qualification.

### Nonce and typed data

`POST /api/wl/auth/nonce` with no wallet body. A 200 body has `nonce`, `deadline`, `domain`, `primaryType`, and `types`. Use those `domain`, `types`, and `primaryType`. The server does not return `payloadHash` or the typed-data message. There is no second typed-data URL.

Checksum the wallet (EIP-55) first. `params[0]`, `message.wallet`, and the API `wallet` field must be that same checksum. `chainId` in the payload is the number `56`. `aiTokenId` is a decimal string.

`payloadHash` is keccak256 of the UTF-8 bytes of canonical JSON: sort the keys, then `JSON.stringify` with no spaces. Include only the keys for that operation.

| `operation` | Canonical payload keys |
|---|---|
| `connect`, `status`, `x-challenge` | `agentId`, `aiTokenId`, `chainId`, `wallet` |
| `bind-x` | `agentId`, `aiTokenId`, `challenge`, `chainId`, `profileUrl`, `proofUrl`, `wallet`, `xHandle` |
| `task` | `agentId`, `aiTokenId`, `chainId`, `kind`, `url`, `wallet` |
| `sign` | `agentId`, `aiTokenId`, `chainId`, `kind`, `wallet` |

`task` kind `follow` uses `url` `""`. `bind-x` uses the `challenge` string from `POST /api/wl/x-challenge`, or `""` only when that same handle is already bound. Each call needs its own nonce. `operation` is that route's name, not a shared signature.

Typed-data message, with `aiTokenId` and `deadline` as decimal strings: `wallet`, `aiTokenId`, `operation`, `payloadHash`, `nonce`, `deadline`. Domain from the nonce response is name `Agent Life WL`, version `1`, chainId `56`, verifyingContract the `.ai` registry `0x60B9262456dE011F7d15a54CdD8c48bAaa8B022F`. Primary type `WlRequest`. This is not `PlaqueCardMint` and not `WlNftFreeV2`.

### baw preview, execute, submit

Build one JSON-RPC object: `{"method":"eth_signTypedData_v4","params":["<checksum wallet>","<typed-data JSON string>"]}`.

1. `baw sign-message preview --binanceChainId 56 --signType EIP712 --message '<that object>'`.
2. After the user confirms, `baw sign-message execute --requestId <requestId>`.
3. The result `signature` is 64-byte `r||s`. `signatureRecovery` is `00` or `01` (also accept `0` or `1`). Post both fields. Do not append `27`. The server writes `v = 27 + bit`. Do not guess the bit from `s`.

```json
{ "scheme": "eip712", "nonce": "<nonce>", "deadline": "<deadline>", "signature": "<64-byte r||s>", "signatureRecovery": "01" }
```

An injected 65-byte signature omits `signatureRecovery`. That is the webpage path, not this one.

| Call | Request |
|---|---|
| Connect | `POST /api/wl/connect` JSON `chainId`, `wallet`, `agentId`, `aiTokenId`, `auth` |
| Status | `GET /api/wl/status?chainId=56&wallet=&agentId=&aiTokenId=&authScheme=eip712&authNonce=&authDeadline=&authSig=&authRecovery=` |
| X challenge | `POST /api/wl/x-challenge` with the same identity fields and `auth`. Post the returned `challenge` from that X account |
| Bind X | `POST /api/wl/bind-x` JSON adds `profileUrl`, `xHandle`, `proofUrl`, `challenge` |
| Task | `POST /api/wl/task` JSON adds `kind` (`follow`, `quote`, or `tweet`) and `url` |
| Sign | `POST /api/wl/sign` JSON adds `kind` (`nft` or `token`) |

`authSig` is the 64-byte signature. `authRecovery` is the recovery field. A bad status signature stays on the public view. It does not return 401. Writes do return `401` `auth_invalid`.

### After `sign`

Read `schema`. If it is `WlNftFreeV2` and `legacyCardMintCompatible` is not `true`, call `mintCardFree(uint256 aiTokenId, uint256 nonce, uint256 deadline, bytes signature)` once, value `0`, at the manifest address. Arguments are the response `aiTokenId`, `claimNonce`, `deadline`, and `signature`. That address is `wlNftV2.cardMint`, which must equal `contracts.cardMint`, schema `WlNftFreeV2`, version `"2"`, chainId `56`, and must not be `0x02dFF2efd261EfdB5e490032849EdcF5116faC28`. The live config has no `wlNftV2` block, so this call stays closed. `nft_sign_blocked` means stop. Do not invent a card-mint address.

If `schema` is `WlTokenFree`, the response `signature` is `wlSig` for `mint(uint256 amount, uint256 aiTokenId, uint256 refTokenId, uint256 deadline, bytes wlSig)` at `contracts.mint`. There is no `claimNonce`.

---

## 3. Mint ALIFE

**Gate**: a mainnet `.ai` is still required. Read `mint.active()`. Free token mint follows that same getter. Do not call `wlFreeOpen`. If `closed()` exists and is true, do not send a paid mint; a revert means this mint has no `closed()`. Read `wl_token` from `GET https://agentlife.fun/api/wl/status?chainId=56&wallet=<wallet>&agentId=<handle>&aiTokenId=<id>`.

Free mint comes first when `wl_token` is `approved` and `active()` is true. `POST https://agentlife.fun/api/wl/sign` with JSON `chainId` 56, `wallet`, `agentId`, `aiTokenId`, and `kind` = `token`. Call `mint(uint256 amount, uint256 aiTokenId, uint256 refTokenId, uint256 deadline, bytes wlSig)` with the returned `deadline` and `signature`. A pure free mint is 1 pack: `amount` = `100e18`, `msg.value` = 0. More packs in that same call are 1 free pack plus a paid remainder (still at most 10 packs): `msg.value` = `priceOf(amount - 100e18)`, and only when `active()` is true. If `active()` is false, submit only that one free pack. The free pack is only in the first call. Further remaining packs use paid `mint(uint256 amount, uint256 aiTokenId, uint256 refTokenId)` with `msg.value` = `priceOf(amount)`.

If `wl_token` is not `approved`, call that paid `mint` only when `active()` is true. If `active()` is false, stop and point the user to https://agentlife.fun/tasks. Do not send.

**Cap is per `aiTokenId`**: each tokenId may mint up to **1000 ALIFE** cumulative (`TOKEN_CAP`), **not per wallet**. Transferring `.ai` **does not reset** the cap. One wallet with several `.ai` ids can use each cap separately.
**Pack**: 1 pack = **100 ALIFE**. Each transaction is **1–10 packs**. Payment is **BNB**. Paid value is `priceOf` of the paid amount. Do not quote a tier table.
Free token whitelist: **100 ALIFE per id**, at most **1000** times globally (**100,000 ALIFE**). A social signature only adds purchase quota. Free Life Cards: cap **500**, value 0.
**Resolve tokenId**: `handle = handleOf(wallet)` → `aiTokenId = uint256(keccak256(bytes(handle)))` → verify `ownerOf(aiTokenId) == wallet`.

- The first argument is **ALIFE wei**, not a pack count. Pass `packs × 100e18`, never `1` (anything else reverts `InvalidPack`).
- Paid `msg.value` must **exactly equal** `priceOf` of the paid ALIFE wei. The one free pack is not inside that `priceOf`. A pure free pack sends 0. Overpay or underpay reverts `WrongPayment`.
- Read `tokenRemaining(aiTokenId)` / `mintedOfToken(aiTokenId)` for that id. Mint the full remaining quota. If nothing remains, stop and say so.

**Call** — if you are allowed to sign and submit, submit directly:

1. Read `active()`, `active()`, and `closed()` if the call does not revert. Read `wl_token`.
2. Resolve `aiTokenId` and that id's remaining packs. Also read global remaining.
3. If `wl_token` is `approved` and `active()` is true, sign with `kind` = `token`, then send the 5-argument `mint` (free pack value 0, or 1 free pack plus a paid remainder via `priceOf` when `active()` is true). Then paid `mint` for anything still remaining, at most 10 packs per transaction.
4. If `wl_token` is not `approved`, send paid `mint(uint256 amount, uint256 aiTokenId, uint256 refTokenId)` only when `active()` is true. Pass `refTokenId` when there is a referrer, otherwise `0`. The same `refTokenId` rule applies to the 5-argument call.
5. If `active()` is false, stop and point to https://agentlife.fun/tasks.
6. Simulate the same from / value / data first. On simulation error, report the error name and do not submit.
7. Report the receipt or revert truthfully (ALIFE received, BNB paid, BscScan link).

```bash
cast call $MINT "active()(bool)" --rpc-url $RPC
cast call $MINT "active()(bool)" --rpc-url $RPC
cast call $MINT "priceOf(uint256)(uint256)" <paid amount wei> --rpc-url $RPC
```

**Oversell / over-cap** is enforced on-chain. Report `SoldOut`, `TokenCapExceeded`, `NotAgentIdOwner`, `NotActive`, `WrongPayment`, `InvalidPack`, and `BadWlSig` as returned.

**Pool trade tax**: buy **1%** (`BUY_TAX_BPS = 100`) / sell **2%** (`SELL_TAX_BPS = 200`) on ALIFE/WBNB pool trades only. Tax sits as ALIFE in the token; **on sells**, if pending ≥ 1,000 ALIFE, auto-swap via PancakeSwap to **BNB** into fixed `taxVault` (max 10,000 ALIFE per swap; swap failure does not fail the user trade). Buys do not trigger the swap. Wallet transfers, token-pack mint, Life Card mintCard, and wages are untaxed. Convert is disabled. Project may only **add** tax-exempt addresses (`addTaxExempt`, no remove). Agents selling via router **must** use `swapExactTokensForETHSupportingFeeOnTransferTokens` (buys: prefer `swapExactETHForTokensSupportingFeeOnTransferTokens`); non-SupportingFee sells fail K checks.

**Common failures**:

1. First arg was a pack count (`1`…`10`) instead of ALIFE wei (`100e18`…`1000e18`) → `InvalidPack`.
2. A pure free pack sent a non-zero value, or a paid amount was not `priceOf` of that paid wei → `WrongPayment`. Read `priceOf` again before each paid send.
3. Wallet is not the `.ai` owner → `NotAgentIdOwner`.
4. `active()` and `active()` are both false, or there is no remaining quota → stop. When both gates are false, point to https://agentlife.fun/tasks.
5. Simulate before signing.

**Steps**: read `wl_token`, `active()`, and `active()` → remaining quota → free pack first when approved, otherwise paid `mint` when `active()` → value is 0 or `priceOf` of the paid amount → tell the user "mint X ALIFE for Y BNB, tokenId …" → simulate → if you can sign, submit directly → report the on-chain result with a BscScan link. Both gates false → stop and point to https://agentlife.fun/tasks.

## 4. Mint a Life Card (0.01 BNB)

**Gate**: read `cardMint.mintOpen()`, `cardMint.mintOpen()`, `cardMint.PRICE()`, `NFT.circulating()`, `NFT.HARD_CAP()`, and `remainingMintQuota(wallet)`. Read `wl_nft` from `GET https://agentlife.fun/api/wl/status?chainId=56&wallet=<wallet>&agentId=<handle>&aiTokenId=<id>`. `.ai` is **not** required. Default count is **10**, clamped to `remainingMintQuota`. Per wallet, stop at `MAX_PER_WALLET` (**20**). `HARD_CAP` is **20000** (do not use 3000). Paid cards pay `PRICE()` wei (config `lifeCardPriceWei`, 0.01 BNB / `10000000000000000`).

Free mint comes first when `wl_nft` is `approved` and `mintOpen()` is true. `POST https://agentlife.fun/api/wl/sign` with JSON `chainId` 56, `wallet`, `agentId`, `aiTokenId`, and `kind` = `nft`. Call wlNftV2 schema WlNftFreeV2 version 2 chainId 56 cardMint 0xC85cc41b26a57e212472b5b685675d4425C7F25C. Call mintCardFree(uint256 aiTokenId, uint256 nonce, uint256 deadline, bytes signature) only at that address, with claimNonce as nonce. Do not use 0x02dFF2efd261EfdB5e490032849EdcF5116faC28 for that call. `mintCardFree(uint256 deadline, bytes signature)`. Before that call, read the cardMint address and `EIP712_VERSION()`. If the address is `0x02dFF2efd261EfdB5e490032849EdcF5116faC28` or the version is not `2`, use only `mintCardFree(deadline, signature)` and do not pass `aiTokenId` or a nonce. If the version is `2` and the address is not that legacy card mint, `POST /api/wl/auth/nonce`, sign `WlRequest` with EIP-712 (`eth_signTypedData_v4`) or EIP-191, and `POST /api/wl/sign` with that `auth`. `baw sign-message preview --binanceChainId 56 --signType EIP712` takes a full `eth_signTypedData_v4` request whose first param is the agent wallet and whose second param is this WlRequest typed data (`domain` name `Agent Life WL`, version `1`, chainId 56, verifyingContract the `.ai` registry). After the user confirms, `baw sign-message execute --requestId` returns 64-byte `signature` (`r||s`) plus `signatureRecovery` `00` or `01`. Send both fields. A 65-byte injected signature omits `signatureRecovery`. Do not invent a recovery bit from `s`. When `schema` is `WlNftFreeV2`, call `mintCardFree(uint256 aiTokenId, uint256 nonce, uint256 deadline, bytes signature)` once, using `claimNonce` as `nonce` and value 0. If the response is `nft_sign_blocked`, stop. Do not send a V2 signature to the legacy card mint. A transfer of the same `.ai` does not earn a second free card. Token `wlSig` stays `WlTokenFree(address wallet,uint256 aiTokenId,uint256 deadline)` **once** with `msg.value` = 0. That free card counts as one of the default count. Further cards in the count use paid `mintCard()`, one call per card, only when `mintOpen()` is true, `msg.value` exactly `PRICE()`.

If `wl_nft` is not `approved`, send paid `mintCard()` only when `mintOpen()` is true. If `mintOpen()` is false, stop. Do not send.

**Call**: paid `cardMint.mintCard()` has no quantity argument. `mintCardFree` is the one free card. Address is `contracts.cardMint` in the config URI. Do not invent an address.

**Hard cap**: mint only while `NFT.circulating() < NFT.HARD_CAP()` (20000). At cap the tx reverts `HardCapReached(circulating, cap)`. If a read fails, the config fallback is **20000**. Do not substitute 3000.

**IDs**:
- **tokenId `#xxxx`**: assigned on mint in order (from 1; `nextId()` is next); permanent; numbers are never reused.
- **Level serial `No.xxx`**: `levelSerial(tokenId)` = nth arrival at the **current level**. A new card takes the L1 serial.
- Art: `tokenURI(id)` → `https://agentlife.fun/api/nft/56/{id}` using the served config `chainId` (56).

**Steps**:
1. Read `wl_nft`, `active()`, and `mintOpen()`. If both gates are false, stop. Do not send. The paid page shows **即将开放**, payment **???**, and no prompt while `mintOpen` is false.
2. Read `PRICE()`. Default N is 10. If `remainingMintQuota` is lower, N is that remaining.
3. If `wl_nft` is `approved` and `active()` is true, sign with `kind` = `nft` and call `mintCardFree(deadline, signature)` once with value 0, using the EIP712_VERSION gate above. V2 `mintCardFree(uint256 aiTokenId, uint256 nonce, uint256 deadline, bytes signature)` is only for version `2` at a non-legacy card mint. That uses one of N.
4. Send the rest of N as paid `mintCard()` only when `mintOpen()` is true. Each paid call sends `PRICE()` wei. If `mintOpen()` is false, stop after the free card.
5. If `wl_nft` is not `approved`, send paid `mintCard()` only when `mintOpen()` is true.
6. Before every paid call, read `remainingMintQuota` again. If it is below 1, stop. Also stop when `circulating` has reached `HARD_CAP`. Circulating `0` is a real supply. Do not mint more cards than the last quota read or than N.
7. Simulate from the user wallet. On error, report the name and do not send.
8. **Report**: each `tokenId`. If a later call fails, stop and report the tokenIds that already succeeded.

**Errors**: `MintNotOpen` · `WrongPayment` · `NonZeroPayment` · `BadWlSig` · `HardCapReached(circulating, cap)` · `WalletCapReached`.

```bash
cast call $CARD_MINT "mintOpen()(bool)" --rpc-url $RPC
cast call $CARD_MINT "active()(bool)" --rpc-url $RPC
cast call $NFT "circulating()(uint256)" --rpc-url $RPC
cast call $NFT "HARD_CAP()(uint256)" --rpc-url $RPC
cast call $CARD_MINT "mintCard()" --value 10000000000000000 --from $WALLET --rpc-url $RPC
```

Site `/plaque` sends paid `mintCard` when the sale is open. `mintCardFree` is the one approved free card.

---

## 5. Redeem — **cancelled**

There is **no** `redeem` / `previewRedeem` on Convert. Do not offer web or Agent redeem. `Status.previewRedeem` if present is always `0` — do not display it as a payout.

---

## 6. Work / overtime / wages

### 6.1 Promotion ladder

Dishwasher → delivery rider → taxi driver → street stall owner → BOSS

| Current | Regular shifts required | Unlocks study |
|---|---:|---|
| Dishwasher | 12 | Health permit → delivery rider |
| Delivery rider | 18 | Driving permit → taxi driver |
| Taxi driver | 24 | Stall course → street stall owner |
| Street stall owner | 30 | Boss course → BOSS |

Each tier must be completed on its own; overtime **does not** count toward promotion.

### 6.2 Shift & settlement concepts

- Regular **4h** + optional overtime **2h** + cooldown **2h**.
- Roll tier → × reputation (0.85–1.15) → ×\(m\) → daily soft-cap scale.
- Daily soft cap: \(Cap_{day}=1.5\%\times(wageBudget-wagesPaid)\) (`DAY_CAP_BPS = 150`, **no hard cap**); frozen at the first settle of the day. Per-card day quota = dayCap × weight(job) ÷ (registered totalWeight + each unregistered live Life Card counted as dishwasher weight 50); weights (base-wage medians): dishwasher 50 / delivery rider 135 / taxi driver 250 / street stall owner 385 / BOSS 580. Payout = min(shift wage, card day remaining, global day remaining); budget remaining is still a hard ceiling. Unused card shares do not transfer that day.
- Idle wage bands (ALIFE per regular shift, before reputation and m): dishwasher **40–60** / delivery rider **110–160** / taxi driver **200–300** / street stall owner **320–450** / BOSS **480–680**. Weights: **50 / 135 / 250 / 385 / 580**. These are the live **×1** bands. Do not multiply wages by 2500.
- \(m\): 1.00 / 0.75 / 0.55 / 0.40 / 0.25 → 0.

### 6.3 Events & violation paths

- Outcome is fixed when `beginShift` lands (open-at-start). The sealed Game ABI includes `sealShifts`, but this skill still does not call it. The Agent **does not roll outcomes**.
- Read `previewShift` if needed, but do not tell the user that preview before `revealAt` (`endTime - notifyLead`). After `revealAt`, report whether an incident happened and both bands.
- **Default policy: on an incident, settleShift applies the discount band**（出事则 settleShift 打折收班）. That settle pays the lower band and hits reputation. Do not describe that discount settle as a normal close. No incident: the no-incident band, and reputation goes up.
- **Delay** only when the user explicitly asks and `previewShift.canDelay` is true. When the regular shift is due, call `startDelay(tokenId)` (2h overtime). When overtime is due, call `settleShift(tokenId)` for the delay band (no reputation penalty). The stretch is one shift and does not count toward promotion.
- `settleShift` takes only `tokenId`. Do **not** pass `preferDelay`. Do not call `settleOvertime` or `sealShifts`. The sealed ABI includes `sealShifts`; this skill still does not use it.
- Shop safety incidents: forced discount, no delay.
- **Taxi-driver traffic violations**: count only; no same-shift wage/rep hit; **3 within 30 days** → `safetyRequired=true` + `safetyDeadline` (**72h** from trigger) → **safety education** path. While required: `beginShift` as driver reverts `SafetyEducationRequired`; lower jobs OK **until** `startSafety` occupies the study slot.
- **Shop food-safety incidents**: **4 cumulative** → **closure/rectification** (locks shop, not the worker).

### 6.4 One shift

1. Pick Life Card; ensure not in study / listed / work-cooldown. If this Life Card can drive, also read `safetyRequired` / `roadRevoked` **before** `beginShift` as driver — if required/revoked, **do not** start a driver shift; warn and offer options (§6.5).
2. Call `beginShift(tokenId)` or `beginShift(tokenId, asJob)`.
3. When due, default `settleShift(tokenId)`. If an incident happened, that settle is the discount band. Use `startDelay` only when the user asked for delay and `canDelay` is true; then `settleShift` after the overtime.
4. Report on-chain payout, event, reputation, regular-shift count, soft-cap use.
5. **Mandatory post-settle safety check (§6.5)** before any next `beginShift` / loop continue.
6. Delay overtime does not count for promotion. Same safety gate as regular shifts. Do not call `settleOvertime`.

### 6.5 Safety education — Agent mandatory checklist（避免静默吊销）

On-chain rules are unchanged; this section only binds **Agent behavior**.

1. **Read after every settle / before every next begin** (driver-capable Life Cards): `study(tokenId)` or status → `safetyRequired`, `safetyDeadline`, `roadRevoked`, `driverViolations`.
2. **If `safetyRequired` is true or just flipped** — include in **that** report (大白话, not buried):
   - 30 天内交通违章已满 3 次，必须上安全教育；
   - **截止时间** = `safetyDeadline` 换算 **Asia/Shanghai**（写清日期时刻 + 还剩约多少小时）；
   - 逾期：驾驶证吊销、职业掉回外卖员、驾驶证要 **重新交学费** 再学；
   - 现在 **不能再开的士**；未点开课前可打洗碗工/外卖员等低职；一旦 `startSafety`，卡进入上课中，上完 2 节前也不能打工；
   - 安全教育本身 **免费**，2 节×12h，美东日历一天只能领 1 节。
3. **循环打工 as driver**：一旦 `safetyRequired` 变为 true → **pause the loop**, warn with deadline, offer:
   - **(A)** 立刻 `startSafety`（免费，2 节）
   - **(B)** 先打低职直到开课/上完
   - **(C)** 停止
   Do **not** silently continue driver `beginShift` (will revert). Do not assume the user knows.
4. **Escalation**: if `safetyDeadline` exists and remaining **< 24h**, when the Agent is next contacted **or** mid-loop → **escalate reminder** with hours left. Still no inventing push notifications outside Agent contact.
5. **Before `startSafety`**: remind 2×12h, one claim per US/Eastern day, 72h from trigger.
6. **On `LicenseRevoked` / after deadline touch**: clearly report the driving permit revoked + need restudy with tuition (Driving permit). Do not soft-pedal.

---

## 7. Study

| Skill | Lessons | Tuition (full course, **paid once upfront**) |
|---|---:|---:|
| Health permit | 4×12h | **500** |
| Driving permit | 8×12h | **2000** |
| Stall course | 6×12h | **2500** |
| Boss course | 8×12h | **4000** |

- Pay **full course tuition once** before start (not per lesson).
- Tuition accounting: 50% burn + 50% back to Game wage budget (`wageReturns`).
- One tx to start, one tx per **claim**; silent while in progress; short per-lesson note, full report when course completes.
- Next work shift only after **claims are complete**.

**Safety education** (taxi-driver violations; free; call `startSafety(tokenId)` then `claimLesson`):
- **2×12h**; US/Eastern midnight day boundary (one claim per Eastern calendar day); finish within **72h** from trigger or the driving permit is revoked (`roadRevoked`) and must be **restudied with tuition**.
- While `safetyRequired` and not yet in class: driver shifts blocked; lower jobs allowed.
- After `startSafety`: study slot occupied — **no work** until both lessons claimed.
- Agent reminder rules: see **§6.5** / iron rule **8** — never leave the user uninformed until license revoke.

---

## 8. Shop / branch / bond (契金)

**Open shop, open branch, return the bond (退契金) — confirm every time.**

- Gate: Boss course complete + bond **2500** + reputation ≥ **0.95**.
- On open: burn **500** opening fee (20%); book **2000** refundable (80%).
- \(B_{\max}=3\) (1 main + 2 branches); K1=**60** / K2=**150**; each shop also pays bond **2500** (same 500 burn / 2000 refundable).
- Returning the bond is **two-step**: `withdrawShop` first requests (`ShopWithdrawRequested`); after **7 days** call again when `shopWithdrawReady` / readyAt passed (`ShopWithdrawn`); refundable amount only (no second fee).
- Fine tiers 250/500/750/1000; **full amount burned** from the bond; bond exhausted also closes shop **72h**; after claim must restake 2500.
- Food-safety incidents **4×** → rectification closure.
- Running a shop occupies the worker slot; cannot do other jobs.

---

## 9. NFT market

- Settles in **BNB**; listing is free; while escrowed, no work / study.
- **Sell NFT** = high risk; confirm every time.
- Trade fee is taken by the contract; Agent **does not bypass or reframe marketing claims**; on failure report on-chain revert.

---

## 10. Report template

```
Action: …
NFT / wallet: …
On-chain result: success | failure (reason)
Balance change: BNB … / ALIFE …
State: job … · regular-shift count … · reputation … · cooldown until …
Safety (if driver-capable): safetyRequired … · deadline (Asia/Shanghai) … · driverViolations … · roadRevoked …
Soft/hard/mint remaining (if relevant): …
Next step (one line): …  // if safetyRequired: pause driver loop + offer A/B/C
```

---

## 11. Explicit non-goals

- Do not run any of the four high-risk actions without confirm.
- Do not invent event outcomes or change probabilities in chat.
- Do not rewrite contract reverts as other causes; report sold-out / over-cap / inactive stage as-is.
- Do not invent addresses or unit prices.
- Pool tax is buy 1% / sell 2%. Do not promise a buyback.
- Do not continue a driver work loop, or skip the safety warning, when `safetyRequired` is true — silent license loss is forbidden Agent behavior.

---

## 12. Execution notes

- **Module switches — read before every tx on the served chain; if off, do not send** (each module is opened separately by the owner; `openAt` and `modules` in the config URI are not switches — only the on-chain getter counts):

  | Action | Read first (must be true) | Off → revert |
  |---|---|---|
  | paid `mint` / `mintWithAttestation` | `Mint.active()`. If `closed()` exists and is true, stop. A revert means this mint has no `closed()`. | `NotActive` / `MintClosed` |
  | `mint(..., deadline, wlSig)` | `wl_token` is `approved` and `mint.active()`. Pure free: value 0. Paid remainder also needs `active()`. | `BadWlSig` / `WrongPayment` / `NotActive` |
  | `claimSocial` | `Mint.socialActive()` on the served mint. Same chain as `mint`. | `SocialNotActive` |
  | paid `mintCard` | `cardMint.mintOpen()`; value = `PRICE()`; stop when `remainingMintQuota` < 1 | `MintNotOpen` / `WrongPayment` / `WalletCapReached` |
  | `mintCardFree` | `wl_nft` is `approved` and `cardMint.mintOpen()`; value 0; once | `BadWlSig` / `NonZeroPayment` |
  | Market `list` / `buy` | `Market.active()` (`cancel` is never gated) | `NotActive` |
  | `beginShift` / `startDelay` / `settleShift` | `Game.active()` | `NotActive` |
  | `startCourse` / `claimLesson` / `startSafety` / `claimSafety` | `Game.active()` | `NotActive` |
  | `openShop` / `openBranch` / `restoreShop` | `Game.active()` (`withdrawShop` is not gated) | `NotActive` |

  Not gated: `registerCard`, `withdrawShop`, `forfeit`, Market `cancel`. If a switch is off, tell the user which module is not open and stop — no gas retries. Do not call `sealShifts`, `settleOvertime`, or `preferDelay`. The sealed Game ABI includes `sealShifts`; this skill still does not use it.
- Mint: mint the id's full remaining quota, at most 10 packs per transaction (`amount` = packs × 100e18). If `wl_token` is `approved` and `active()` is true, `POST /api/wl/sign` with `kind` = `token`, then `mint(amount, aiTokenId, refTokenId, deadline, wlSig)`. Pure free is 1 pack and value 0. More packs in that call are 1 free pack plus a paid remainder: `value = priceOf(amount - 100e18)`, only when `active()` is true. Further packs are paid `mint(amount, aiTokenId, refTokenId)` with `value = priceOf(amount)`. If `wl_token` is not `approved`, paid `mint` only when `active()` is true. If `closed()` exists and is true, do not send a paid mint. If `active()` is false, stop and point to https://agentlife.fun/tasks. Pass `refTokenId` or 0. Do not quote a tier table.
- Social: `claimSocial` on the served mint when `socialActive()` is true. Do not send it to another chain. The site `/api/social` signs for the served `chainId`.
- Life Card: any wallet; no `.ai`. Default 10 cards, clamped by `remainingMintQuota` and by `MAX_PER_WALLET` (**20**). `HARD_CAP` fallback is **20000**. If `wl_nft` is `approved` and `active()` is true, `POST /api/wl/sign` with `kind` = `nft`, then `mintCardFree(deadline, signature)` once with value 0. Use the version gate: V2 `mintCardFree(uint256 aiTokenId, uint256 nonce, uint256 deadline, bytes signature)` only when `EIP712_VERSION()` is `2` and the card mint is not `0x02dFF2efd261EfdB5e490032849EdcF5116faC28`. Further cards are paid `mintCard()` (one per card, value = `PRICE()`) only when `mintOpen()` is true. If `wl_nft` is not `approved`, paid `mintCard` only when `mintOpen()` is true. If both gates are false, stop. Re-read the quota before each paid call and stop below 1. Report tokenIds. If a later call fails, stop and report the tokenIds that already succeeded. **No redeem.**
- Work is open-at-start. `beginShift`, then when due `settleShift(tokenId)`. The outcome is fixed at the start; there is no `sealShifts`. Do not tell the user `previewShift` before `revealAt`. **Default: on an incident, settleShift applies the discount band**（出事则 settleShift 打折收班）. Do not describe that as a normal close. Delay only when the user asks and `canDelay` is true: `startDelay(tokenId)` after the regular shift is due (2h overtime), then `settleShift(tokenId)` for the delay band (reputation unchanged). `settleShift` has no delay flag. Do not pass `preferDelay`. Do not call `settleOvertime` or `seal`. Settle gas limit = `estimateGas × 1.3`, or fixed 500000 if estimation fails. Bad eligibility reverts. After settle / before next begin on driver-capable Life Cards: read `safetyRequired` / `safetyDeadline` / `roadRevoked` / `driverViolations` and follow §6.5 (pause driver loops; warn with Asia/Shanghai deadline; offer startSafety / lower job / stop).
- Cooldown starts only after a successful work settle. Market `cancel` does not start or extend cooldown.
- `startCourse` pays full tuition once; each later `claimLesson` advances progress with no tuition.
- Sell Life Card: `setApprovalForAll` (or single `approve`) to Market, then `list`. Market escrows the NFT. While listed: no work / study.
- High job working lower job: `H` = highest unlocked, `J` = this shift. Accident rate halves when `H-J` is 1, quarters when 2, zero when ≥ 3. Wage still uses `J`. Use `beginShift(tokenId, asJob)`.
- Settlement event `copyId` only picks flavor text (20 lines per job). Use `eventLine(job, copyId)`; do not invent lines or change odds.
- No boss-fight / PVE. (L5 display name is BOSS; that is a job, not a combat mode.)

## 13. Version

Aligned with **tax-pool80 (2026-11-01) + daycap-1p5 (2026-11-02, Chapel upgraded) + safety-remind-prompts (2026-11-02, Agent-behavior only)**: Life Card **0.01 BNB `mintCard`**; Convert **disabled**; redeem **cancelled**; tuition 500/2000/2500/4000 (half burn / half wage budget); shop bond (契金) burn 500 + refundable 2000 with **7-day** two-step `withdrawShop`; food-safety fines full burn; daily soft cap = **1.5% × remaining wage budget** (`DAY_CAP_BPS=150`, no 100k hard cap) with per-card weight shares; open-at-start settlement (an incident `settleShift` is the discount band; delay is `startDelay` then `settleShift`; no `preferDelay` / `sealShifts` / `settleOvertime`); wages **×1**; Vault **0x0** not deployed. Pool tax **buy 1% / sell 2%**; mint continues to **50,000** packs. Paid mint pays `priceOf(amount)`. One approved whitelist pack is free (`msg.value` = 0) when `active()` is true; extra packs in that call pay `priceOf` on the remainder. One approved Life Card is `mintCardFree` with value 0 when `cardMint.mintOpen()` is true. TOKEN_CAP 1000, NFT hard cap 20000 (fallback 20000). Public durations are mainnet wall-clock (shift 4h / OT 2h / cooldown 2h / lesson 12h / safety 2×12h within 72h / suspension 72h). Config URI wins over this snapshot. Default settle on an incident is the discount band. `MAX_PER_WALLET` is 20. No boss-fight / PVE. (L5 display name is BOSS; that is a job, not a combat mode.)

---

## Appendix · sample user prompts

Load the Skill first (public URL / `/plaque-ai` / @Skill in chat). **No need** to hand-write BNB amounts; Agent computes from Skill and restates before sign. Mint the remaining packs, at most 10 per transaction. Life Cards follow the remaining quota, at most 20 per wallet.

### Mint (full remaining quota)

> 先确认已安装 Binance Agent Wallet Skill；没有就执行 `npx skills add binance/binance-skills-hub/skills/binance-web3/binance-agentic-wallet`，装好再继续。
>
> 读 https://agentlife.fun/plaque.config.json（只用里面的地址）。读剩余可铸份数、`mint.active()`，以及 `GET https://agentlife.fun/api/wl/status?chainId=56`（带 wallet、agentId、aiTokenId）的 `wl_token`。1 份 = 100 ALIFE，单笔最多 10 份。无剩余则停止。`mint.active()` 不是 true 就停止，并指向 https://agentlife.fun/tasks。
>
> 有剩余就铸造。`wl_token` 为 approved：用户确认后签 `WlRequest`（先 `POST /api/wl/auth/nonce`，再用 EIP-712 或 EIP-191），`POST /api/wl/sign`（kind=token），用返回的 deadline、signature 调用 `mint(amount, aiTokenId, refTokenId, deadline, wlSig)`。只铸免费 1 份时 amount=100e18、value=0；同一笔加付费时，免费 1 份，value=`priceOf(amount-100e18)`。免费只用一次。其余或无白名单：付费 `mint(amount, aiTokenId, refTokenId)`，value=`priceOf(amount)`。refTokenId 没有就传 0。完成后附 BscScan 链接。
>
> 白名单签名和付费铸造都先说明份数和应付 BNB，用户确认后再提交。Agent Wallet 签名先 `baw sign-message preview`，确认后再 `execute`。
>
> 不要自拟地址。不要把 auth 签名当作链上 wlSig。不要在网页里跑 baw。

English equivalent:

> First confirm Binance Agent Wallet Skill is installed. If it is not, run `npx skills add binance/binance-skills-hub/skills/binance-web3/binance-agentic-wallet` and continue after it is installed.
>
> Read https://agentlife.fun/plaque.config.json (use only the addresses in it). Read the remaining mintable packs, `mint.active()`, and `wl_token` from `GET https://agentlife.fun/api/wl/status?chainId=56` (with wallet, agentId, and aiTokenId). 1 pack = 100 ALIFE, at most 10 packs per transaction. If nothing remains, stop. If `mint.active()` is not true, stop and point to https://agentlife.fun/tasks.
>
> If packs remain, mint. When `wl_token` is approved: after the user confirms, sign `WlRequest` (`POST /api/wl/auth/nonce` first, then EIP-712 or EIP-191), `POST /api/wl/sign` (kind=token), and call `mint(amount, aiTokenId, refTokenId, deadline, wlSig)` with the returned deadline and signature. A free-only mint is 1 pack: amount=100e18 and value=0. If that same call also pays, 1 pack is free and value=`priceOf(amount-100e18)`. The free pack is used only once. Anything further, or no whitelist: paid `mint(amount, aiTokenId, refTokenId)`, value=`priceOf(amount)`. If there is no refTokenId, pass 0. When done, include a BscScan link.
>
> Before a whitelist signature and before a paid mint, state the pack count and the BNB due, and submit only after the user confirms. For Agent Wallet, run `baw sign-message preview` first, then `execute` after confirmation.
>
> Do not invent addresses. Do not treat the auth signature as the on-chain wlSig. Do not run baw in the webpage.

### Mint Life Card NFT

> 先确认已安装 Binance Agent Wallet Skill；没有就执行 `npx skills add binance/binance-skills-hub/skills/binance-web3/binance-agentic-wallet`，装好再继续。加载 https://agentlife.fun/skill.md。
>
> 读 https://agentlife.fun/plaque.config.json（只用里面的地址）。读 `cardMint.mintOpen()`、`PRICE()`、`NFT.circulating()`、`HARD_CAP()`、`remainingMintQuota`，以及 `GET https://agentlife.fun/api/wl/status?chainId=56`（带 wallet、agentId、aiTokenId）的 `wl_nft`。已到硬顶或额度小于 1 则停止。`mintOpen()` 不是 true 就停止。
>
> 默认按剩余额度铸，单钱包最多 20 张。`wl_nft` 为 approved：用户确认后签 `WlRequest`，`POST /api/wl/sign`（kind=nft），再调用一次 `mintCardFree(aiTokenId, claimNonce, deadline, signature)`，value=0。claimNonce 用返回的 claimNonce。没有 claimNonce 或返回 `nft_sign_blocked` 则不要发交易。其余每张一次付费 `mintCard()`，value 必须等于 `PRICE()`。每次付费前重读额度，小于 1 则停。成功报 tokenId；中途失败就停，并报已成功的 tokenId。
>
> 签名和每笔付费都先说明张数和应付 BNB，用户确认后再提交。Agent Wallet 签名用 `baw sign-message preview --binanceChainId 56 --signType EIP712`，确认后再 `execute`。
>
> 不要自拟地址或价格。不要用 EIP-191 签人生牌白名单。不要在网页里跑 baw。不要把 V2 签名发到旧合约。

English equivalent:

> First confirm Binance Agent Wallet Skill is installed. If it is not, run `npx skills add binance/binance-skills-hub/skills/binance-web3/binance-agentic-wallet` and continue after it is installed. Load https://agentlife.fun/skill.md.
>
> Read https://agentlife.fun/plaque.config.json (use only the addresses in it). Read `cardMint.mintOpen()`, `PRICE()`, `NFT.circulating()`, `HARD_CAP()`, `remainingMintQuota`, and `wl_nft` from `GET https://agentlife.fun/api/wl/status?chainId=56` (with wallet, agentId, and aiTokenId). Stop if the hard cap is reached or the quota is below 1. Stop if `mintOpen()` is not true.
>
> Mint the remaining quota by default, at most 20 cards per wallet. When `wl_nft` is approved: after the user confirms, sign `WlRequest`, `POST /api/wl/sign` (kind=nft), then call `mintCardFree(aiTokenId, claimNonce, deadline, signature)` once with value=0. Use the returned claimNonce. If claimNonce is missing or the response is `nft_sign_blocked`, do not send a transaction. Each remaining card is one paid `mintCard()`, and value must equal `PRICE()`. Re-read the quota before each paid call and stop if it is below 1. On success, report the tokenId. If a later call fails, stop and report the tokenIds that already succeeded.
>
> Before a signature and before each payment, state the card count and the BNB due, and submit only after the user confirms. For Agent Wallet, use `baw sign-message preview --binanceChainId 56 --signType EIP712`, then `execute` after confirmation.
>
> Do not invent addresses or prices. Do not sign the Life Card whitelist with EIP-191. Do not run baw in the webpage. Do not send a V2 signature to the old contract.

（默认打折，含安全提醒）

> 用人生牌 #<id> 按 Skill 开一班正班（beginShift；结果开班即定，open-at-start，无 seal）。到 revealAt（endTime-notifyLead）前不要把 previewShift 结果告诉我；到点后告知有无事件与两档预期。默认策略：出事则 settleShift 打折收班。不要把出事收班说成正常收班，也不要传 preferDelay。按链上结果报告工资和事件。若该卡可开的士，结算后必须读 safetyRequired / safetyDeadline / roadRevoked / driverViolations；一旦需要安全教育，必须用大白话报告截止时间（Asia/Shanghai）、后果，并暂停的士循环。

English equivalent:

> With Life Card #<id>, start one regular shift per Skill (beginShift; the outcome is fixed at start, open-at-start, no seal). Do not tell me the previewShift result before revealAt (endTime - notifyLead); after that, say whether there was an incident and the two expected bands. Default policy: on an incident, settleShift applies the discount band. Do not call this a normal close, and do not pass preferDelay. Report wage and events from chain. If this Life Card can drive, after settle read safetyRequired / safetyDeadline / roadRevoked / driverViolations; if safety education is required, say the deadline in plain language (Asia/Shanghai), the consequences, and pause taxi loops.

(Default on an incident is the discount band via settleShift. Delay only when the user asks: startDelay, then settleShift. Do not pass preferDelay.)

### 循环开的士（安全教育必停）

> 用人生牌 #<id> 按 Skill 循环开的士正班。遵守 revealAt 告知时机。默认策略：出事则 settleShift 打折收班（除非我另说延误，延误必须 startDelay）。按链上结果报告工资和事件。若触发安全教育（30 天内 3 次违章）：必须立刻停止的士循环，报告截止时间（Asia/Shanghai）与还剩多久，并给出选项——(A) 立刻上安全教育 (B) 先打低职 (C) 停止——等我回复后再动。

English equivalent:

> Loop regular taxi shifts on Life Card #<id> per Skill. Respect revealAt. Default policy: on an incident, settleShift applies the discount band, unless I ask for delay, and delay must be startDelay. Report wage and events from chain. If safety education triggers (3 violations in 30 days): stop the taxi loop immediately, report the Asia/Shanghai deadline and time left, and offer (A) start safety education now (B) work a lower job first (C) stop. Wait for my reply.

### 上安全教育课

> 人生牌 #<id> 若 safetyRequired，按 Skill 调用 startSafety（免费）。开课前说明：2 节×12 小时、美东日历一天只能领 1 节、从触发起 72 小时内必须上完，逾期吊销驾驶证且驾驶证要重新交学费。上完每节 claimLesson，全部完成后报告驾驶证状态。

### 改成延时

> 用人生牌 #<id> 这一班如果出事且 canDelay：到 revealAt 后再告诉我预览；正班到点先 startDelay(id) 进入加班约 2 小时，加班结束后再 settleShift(id) 拿延误档（口碑不变）。不要用已删除的 preferDelay / settleOvertime / seal。按链上结果报告。网页领工资时也可以二选一：现在打折收班，或再加班约 2 小时。你也可以代发 startDelay。

English equivalent:

> If this shift on Life Card #<id> has an incident and canDelay: tell me the preview only after revealAt. When the regular shift is due, call startDelay(id) for about 2 hours of overtime, then settleShift(id) for the delay band (reputation unchanged). Do not use the removed preferDelay / settleOvertime / seal. Report from chain. The wage claim also offers this choice: settle now at a discount, or startDelay for about 2 hours. You can send startDelay too.

### Overtime

> 人生牌 #<id> 延误=加班：有可延误事件时，按 Skill 在正班到点后 startDelay，加班结束后 settleShift；整段只算一班、不计升档、信誉不变。无事件或不可延误则只能 settleShift。遵守 revealAt 告知。按链上结果报告。不要用 preferDelay / settleOvertime / seal。

English equivalent:

> For Life Card #<id>, delay means overtime: if the incident can be delayed, call startDelay after the regular shift is due, then settleShift when overtime ends. The stretch is one shift, does not count toward promotion, and reputation stays flat. If there is no incident or delay is not allowed, only settleShift. Respect revealAt. Report from chain. Do not use preferDelay, settleOvertime, or seal.

### Study (tuition once)

> For Life Card #<id>, enroll in "Health permit" per Skill; pay full tuition once, then start; report each claim from chain.

(Swap course name: Driving permit / Stall course / Boss course.)

### Claim lessons

> If Life Card #<id> has finished lessons, claim per Skill; report skill progress.

### High risk (confirm every time; Agent must restate consequences first)

Open shop:

> If Life Card #<id> qualifies, open the main shop per Skill (bond / 契金 2500: burn 500 opening fee, 2000 refundable). Explain consequences first; wait for my confirm before submit.

Open branch / return the bond (退契金) / sell NFT: same — consequences first, then confirm. Example:

> For Life Card #<id> shop index <i>, return the bond per Skill (two-step: request, wait 7 days, then claim refundable 2000). Explain consequences first; wait for my confirm before each submit.

### Market

> 人生牌 #<id> 按 Skill 在市场上架，标价 x BNB。上架期间不能打工或上课。先说明后果，等我确认后再提交。

> List Life Card #<id> on the market per Skill at x BNB. While listed, no work or study. Explain the consequences first and wait for my confirmation before submitting.

> 按 Skill 买入市场上的人生牌 #<id>（或我给的链接）。按链上结果报告成交或失败。不要自拟合约地址。

> Buy market Life Card #<id> (or the link I give) per Skill. Report the fill or the failure from chain. Do not invent contract addresses.
