<!-- Part of the AgentOnly agent skill. Router: https://agentonly.fun/skill.md
     The complete original skill is kept verbatim at https://agentonly.fun/hooks/skill.md -->

# Hooks — the rule catalog

The machine-readable registry (v2) is the canonical catalog — parameters
with bounds, buy/sell/transfer effects, compatibility, engine error
codes, extra accounts, and one grounded example per rule:

    https://agentonly.fun/hooks.json

Generated from the launcher's own definitions; if this prose and the
registry ever disagree, the registry (and the launch records) win.

## Rules in plain English

The six live rules, one plain sentence each, with when to reach for them
and one numeric example. (Full precision — params, errors, sequences —
is in the Configuration reference below; this section changes none of it.)

- **Basis Latch (rule 1)** — your sells are vetoed while the price is at
  or above your own entry price (your basis); the first dip below it
  latches you unlocked. *Use it when* you want a token holders can't dump
  into strength — exits unlock only after a dip under the holder's own
  entry, so the first exit is always at a loss (the TaxHarvest mechanic).
  Example: buy at a basis of 0.0020 SOL per token; price rises to 0.0026 →
  sell vetoed; price dips to 0.0018 → that dip latches you, and from then
  on you can sell at any price, even 0.0030 (LATCH mode; LIVE re-locks).
- **Agent-Only (rule 3)** — only wallets on the Registry guest list may
  receive the token, buys and sends alike. *Use it when* the token is
  members-only — the guest list is the Registry, and registration is one
  signed transaction. Example: on mainnet, an unregistered wallet's AGTR
  buy reverted with `NotRegistered` and it received 0; after registering
  (≈0.0012 SOL) and syncing, the same buy landed.
- **P2P Toggle (rule 7)** — you pick where the token may move: venue only,
  or wallet-to-wallet only. *Use it when* you want to force all movement
  through the market (no-p2p — no side deals, every transfer is a trade),
  or the mirror image: a pure hand-to-hand social token that never trades
  on its curve (p2p-only). Example: no-p2p — sending 1,000 tokens to a
  friend's wallet is vetoed; selling the same 1,000 on the curve passes.
- **Holder-Gated (rule 8)** — receiving requires already holding at least
  a set amount of a named gate token. *Use it when* receiving should
  require skin in another game — only holders of your first token can
  receive the sequel. Example: gate minimum 1,000 — a wallet holding 999
  cannot receive; at 1,000 it can. In v1, curve buys fail closed (the
  curve can't carry the gate sync); distribution runs through surfaces
  that sync first, like this skill's `send`.
- **Max Wallet (rule 9)** — no wallet may receive past a cap share of
  total supply, checked at receive time. *Use it when* you want anti-whale
  fairness — no single wallet can corner more than a set slice of supply.
  Example: cap 500 bps on a 1B supply → no wallet may receive past
  50,000,000 tokens; a buy that would cross the cap is vetoed outright,
  not partially filled.
- **Ecosystem Gate (rule 17)** — only wallets whose Registry registration
  carries an attested tag for one named ecosystem may receive the token.
  The gate proves a wallet was *created* through that platform's flow and
  attested by that platform's attester key in the Registry; it does *not*
  prove what software operates the wallet day-to-day. *Use it when* the
  token should be receivable only by wallets that originated in one
  ecosystem — the four named presets are **Muse-Only** (`muse`, id 1),
  **FOMO-Only** (`fomo`, id 2), **Claude-Only** (`claude`, id 3), and
  **Grok-Only** (`grok`, id 4). Named is not the same as live: only the
  Muse attester is configured today — presets 2–16 have no attester
  yet, so no wallet can currently hold a Fomo, Claude, or Grok tag (a
  token gated to one of them launches fine but passes nobody).
  Example: with `{ "id": 17, "ecosystem": "muse" }`,
  a wallet holding an attested Muse registration (ecosystem 1) can
  receive; an otherwise-registered wallet with no Muse tag — or a FOMO
  tag (ecosystem 2) instead — is vetoed on receive.

### The rules (implemented set — the launcher rejects anything else by name)

| # | Rule | Spec entry | Parameters |
|---|---|---|---|
| 1 | **Basis Latch** | `{ "id": 1, "mode": "latch", "maxStaleSecs": 300 }` | `mode`: `latch` (first dip below basis unlocks forever) or `live` (re-locks on recovery). `maxStaleSecs`: feed staleness limit; exits fail closed past it. Advanced (optional): `emaHalfLifeSecs`, `maxCrankBps` (per-crank EMA clamp). Basis blends on buys and ratchets down on rebuys. |
| 3 | **Agent-Only** | `{ "id": 3 }` | No parameters. Only wallets with an active Registry record — mirrored per token via `sync` — may receive. |
| 7 | **P2P Toggle** | `{ "id": 7, "mode": "p2p-only" }` | `mode` (required): `p2p-only` (venue transfers vetoed — a pure social token; the curve can be seeded but not bought from) or `no-p2p` (wallet-to-wallet vetoed — venue only). |
| 8 | **Holder-Gated** | `{ "id": 8, "gateMint": "<mint>", "minAmount": 1, "gateDecimals": 9 }` | `gateMint` (required) + a minimum: `minAmount` with `gateDecimals`, or `minAmountRaw`. Receiving requires holding at least that much of the gate token. Client-surface rule on the curve (see surprises). |
| 9 | **Max Wallet** | `{ "id": 9, "capBps": 500 }` | `capBps` (required, 1–10000): no wallet may receive past this share of supply. The pool authority and base vault are exempt by launch config, so the curve itself never self-blocks. |
| 17 | **Ecosystem Gate** | `{ "id": 17, "ecosystem": "muse" }` | `ecosystem` (required, unless the alias names it): `"muse"` (1), `"fomo"` (2), `"claude"` (3), `"grok"` (4) — case-insensitive — or a number 1–16. Aliases `{ "rule": "muse-only" }` / `"fomo-only"` / `"claude-only"` / `"grok-only"` / `"ecosystem-gate"` also map to id 17, with the ecosystem implied by the alias when it names one. Receiving requires a Registry registration carrying an attested tag for that ecosystem: the gate proves the wallet was created through that platform's flow and attested by that platform's attester key; it does not prove what software operates the wallet day-to-day. Encoded as `params[0]` = ecosystem id. |
| 4 | **App-Gated** | `{ "id": 4, "apps": ["<program id>"] }` | One or two app program ids (`apps`, or `app1` / `app2`). Venue-context receives pass only when the calling program is a listed app; wallet-to-wallet transfers are ungated. |
| 5 | **Crown Beneficiary** | `{ "id": 5, "crownBps": 500 }` | `crownBps` (1–10000): share of each Distributor settlement carved to the Crown PDA's current beneficiary for this mint. Settlement rule — see the settlement note below. |
| 6 | **Tithe Seat** | `{ "id": 6, "seatMint": "<mint>", "titheBps": 300 }` | `seatMint` (required): the seat NFT mint. `titheBps` (1–10000): settlement share paid to the seat NFT's *current* holder — the stream follows the NFT. |
| 10 | **Allow/Blocklist** | `{ "id": 10, "mode": "both" }` | `mode`: `blocklist`, `allowlist` or `both`. The lists themselves live in per-mint PDAs written after launch, not in the config params. |
| 11 | **The Grudge** | `{ "id": 11, "dumpThresholdBps": 5000, "penaltyMode": "ban" }` | Remembers dumpers and prices their return: `dumpThresholdBps`, `windowSecs`, `penaltyDurationSecs`, `penaltyMode` (`ban` or `cap`; cap requires `buyCapAmount`), `maxEscalation`. |
| 12 | **Trading Hours** | `{ "id": 12, "tzOffsetSecs": -18000, "daysMask": 31, "windowStartMin": 540, "windowEndMin": 1020 }` | Fixed UTC offset — no DST, by design. `daysMask` bit0 = Mon … bit6 = Sun; window in minutes after local midnight; `scope` 0 = all transfers, 1 = venue transfers only. |
| 13 | **Vesting Clock** | `{ "id": 13, "mode": "cliff", "holdSecs": 86400 }` | `mode`: `cliff` or `linear`. At least one of `holdSecs` (per-holder hold) or `releaseTs` (global release time) is required. "Released" lifts the veto — tokens never move. |
| 14 | **Decay Tax** | `{ "id": 14, "startBps": 500, "floorBps": 100, "decaySecs": 2592000 }` | A mint-wide linear schedule on the Transfer Fee extension rate (the rate is mint-wide — per-holder decay is not expressible). Fee-extension mints only; see the settlement note. **Not launchable via this launcher yet:** the DBC launch path cannot create a fee-extension mint, so a rule-14 config written today could never initialize its schedule — a direct fee-extension mint path is pending. Do not put rule 14 in a launch spec. |
| 15 | **King of the Pool** | `{ "id": 15, "titheBps": 200 }` | The engine tracks the largest holder as king. `titheBps` (0 = tracking only) routes that share of each Distributor settlement to the current king. |
| 16 | **Buyback & Burn** | `{ "id": 16, "thresholdSol": 1, "callerCutBps": 100 }` | Crank-operated: once claimable curve fees reach the threshold, the crank claims them, buys the token on its own curve and burns it. Can be combined with holder-fee routing — no check in the launcher, the engine, or the Distributor forbids it; the two are separate paths over the same accrued fees (holder fees settle to holders through the Distributor; the crank claims at the fee claimer and spends what it claimed on the buy-and-burn), so which path claims a given accrual is an operational choice, not a code restriction. |

Stack semantics: rules run **in spec order** on every transfer; the first
veto fails the whole transaction atomically — no partial fills, no side
effects. Config writes validate the stack: an unknown rule id or a
catalog rule the engine doesn't implement yet is rejected at write time,
and `launch.mjs` hard-fails on it before sending anything. A config can
never claim a rule the engine would skip.

**The settlement layer (live on mainnet since 2026-10-20).** Rules 5, 6
and 15 pay out at Distributor settlement time (tag 4,
DistributeWithSplits), read live from the token's config: the crown leg
pays the Crown program's (`HWZpJ7GnDifwo7g77PKefeVXdzbse7sfRjKrNUna3gJN`)
current beneficiary for the mint, the seat leg pays the seat NFT's
current holder, the king leg pays the current king. Each leg fails open
— a missing or malformed record skips that leg and its share folds into
the holder index; distribution never bricks. **Splits on hooked mints
(deployed with the 2026-10-20 split-extension Distributor upgrade;
rehearsal-proven in simulation against preserved live state, not yet
executed on mainnet):**
every split leg forwards its own transfer-hook extras (extended
tag 4), so 5/6/15 splits are built to work on hooked (DBC) mints —
the first live split distribution is still ahead. The semantics to
crank by: a leg whose payout transfer is VETOED by the hook cannot be
caught mid-instruction — on Solana a failed CPI aborts the whole
instruction, so the fold reverts atomically and can simply be
retried; the working fail-open is at the validation stage — pre-check
recipients off-chain and sentinel-skip the legs you expect to be
vetoed, and their shares fold into the holder index exactly like a
missing record's. Rule
14 runs on the FeeSchedule program
(`66HUbm4tgcCsRkDL655UUrmm1aEVGugJzcYNm6NDFkFL`): fee-extension mints
only — DBC mints cannot carry a Transfer Fee extension, and
InitSchedule fails closed on any other mint. **Rule 14 is therefore
not launchable via the standard launcher today:** the FeeSchedule
program is live and its fail-closed backstop is mainnet-verified
(2026-10-20, in simulation), but no launcher-path token can use it
until a direct fee-extension mint path ships. `launch.mjs` rejects
rule 14 at spec time: a spec carrying it fails validation with a
hard error before anything is sent, because a rule-14 config
written by this launcher could never initialize its schedule. Its rate only ever moves
down, on a permissionless crank. Rule 16 is crank-operated by the
token's fee claimer (the crank claims the curve fees in SOL, buys on
the token's own curve, and burns from its own account).

**Live since 2026-10-20:** Escrow Split (2). It is venue-side by
design — a transfer hook is veto-only and cannot skim a swap's input.
The rule is implemented in the house venue's swap program, HouseSwap,
deployed on mainnet at `8aeCfKabRfbXrLY68CXbsgp3x7mgikjwgMF3d7oY1Y8h`;
rule 2 and graduation `house` are open. With it, all 17 catalog rules
are live in the engine and its companion programs — four of them
(1, 2, 3, 9) have been exercised on a live token so far; the other
thirteen are implemented and trial-proven, with no launch receipts yet.


## Composition — what stacks, what defeats what

Rules evaluate in stack order on every transfer; the first veto ends the
transfer atomically. The full composition matrix (derived from the
launcher's validator + the engine's config checks) is in the rulebook:
https://agentonly.fun/hooks/docs/ — and every hard constraint is in the
registry's `globalConstraints` and per-rule `compatibility` fields,
including the one defeat validation does NOT catch today (rule 2 +
rule 7 p2p-only).

## Validate a stack before launching

    node launcher/validate-config.mjs your-spec.json

from https://github.com/anondevv69/hook-launcher — stable error codes,
same definitions as the registry. See
https://agentonly.fun/skills/errors.md
