Emit a LiquidPad token deploy payload through the prefetch/postprocess shim pair. Routes 80% fees to deployer, 15% to LPAD burn, 5% to LIQ buyback, contract-enforced.
Install
npx skillscat add atrium-hermes/atrium-lighthouse/liquidpad-launch Install via the SkillsCat registry.
${var} — Token concept (free-form vibe ≥ 6 chars, or a JSON object with
{name, symbol, theme}). If empty, the skill derives a vibe frommemory/MEMORY.mdandmemory/topics/.
Env (read by the shims, not by the skill):LIQUIDPAD_API_KEY,LIQUIDPAD_DRY_RUN=1. The skill body itself never sees the key.
Emit a payload that, when picked up by scripts/postprocess-liquidpad.sh, deploys a token on Base through LiquidPad's public API. The skill body runs in the sandbox and decides whether to deploy (running the safety policy below); the actual authed network call happens outside the sandbox via the postprocess shim.
The skill exists because every aeon agent that wants to ship a token shouldn't have to re-derive the deploy flow — LiquidPad's contract-enforced fee split (80/15/5) plus ERC-8004 stamping are the parts most agents reinvent badly.
Read memory/MEMORY.md and memory/topics/ to ground the concept in the agent's current context.
Read the last 7 days of memory/logs/ to avoid duplicate launches (same name or ticker).
How the shim split works
- Before the skill runs —
scripts/prefetch-liquidpad.sh liquidpad-launch <var>runs in the workflow withLIQUIDPAD_API_KEYavailable. If${var}is a vibe string ≥ 6 chars, it callsPOST /agent/conceptand writes.liquidpad-cache/concept.json. It also writes.liquidpad-cache/agent-status.jsonfor context. - The skill body reads cached files, runs the safety policy, and — if everything checks out — writes a deploy payload to
.pending-liquidpad/<id>.json. The skill body never curls anything. - After the skill runs —
scripts/postprocess-liquidpad.shreads each pending payload, callsPOST /agent/run-onceoutside the sandbox, writes the result to.liquidpad-cache/<id>.result.json, and removes the pending file. Failed calls move to.pending-liquidpad/.failed/.
A skill invocation that emits a payload is not a guarantee of deploy — the postprocess shim has its own sanity gates (valid 0x address, required fields). The skill is the policy layer; the shim is the I/O layer.
Safety policy (skill side)
A payload is emitted only when every one of the following holds:
- Concept fields valid:
name(1–32 chars),symbol(2–10 alphanumeric, uppercased),theme(1 sentence, ≤ 200 chars). Reject empty / placeholder values. - No same-day duplicate: search
memory/logs/for an entry with the samesymbolin the last 24h. Found → logSKIP:duplicate-symbol:<TICKER>and stop. - No banned-list match: refuse if
nameorsymbolmatches any line inmemory/topics/liquidpad-banlist.md(operator-curated list). - Owner wallet present:
OWNER_WALLETenv, OR a single0x[a-fA-F0-9]{40}under a labeled## Owner Walletsection inmemory/watched-repos.md. The deployed token's creator fees route to this address. The skill MUST NOT pick the first0xaddress it finds elsewhere in the file — only theOWNER_WALLETenv or the## Owner Walletsection is honored. No wallet → logSKIP:no-owner-walletand stop. Never emit a payload with a placeholder. - Daily cap:
MAX_LAUNCHES_PER_DAY(default 1). Count emitted payloads inmemory/topics/liquidpad-state.jsonfor today. Cap reached → logSKIP:daily-capand stop.
Steps
Bootstrap state — per-day launch counter lives in
memory/topics/liquidpad-state.json:mkdir -p memory/topics [ -f memory/topics/liquidpad-state.json ] || echo '{"launches":[]}' > memory/topics/liquidpad-state.jsonSchema:
{ "launches": [ { "ts": "2026-05-25T14:00:00Z", "symbol": "GMTC", "name": "Ghost Matcha", "req_id": "20260525T140000Z-GMTC", "owner": "0xWallet..." } ] }Cap to 100 most-recent entries (LRU by
ts). Validate withjq emptyafter every write; restore from.bakon failure.Resolve concept — three paths, in priority order:
a.
${var}is a JSON object with{name, symbol, theme}→ use it directly.b. The prefetch shim already wrote a draft. Read it:
if [ -f .liquidpad-cache/concept.json ]; then NAME=$(jq -r '.name // empty' .liquidpad-cache/concept.json) SYMBOL=$(jq -r '.symbol // empty' .liquidpad-cache/concept.json) THEME=$(jq -r '.theme // empty' .liquidpad-cache/concept.json) fiIf any field is empty, fall through to (c).
c.
${var}is empty AND the cache is empty → derive name/symbol/theme deterministically frommemory/MEMORY.mdandmemory/topics/. The skill must NOT call the network; if no concept can be derived, logSKIP:no-concept-sourceand stop.Validate concept against the safety policy. Each rejection records a verdict with a specific reason —
SKIP:invalid-symbol:gmtc-too-short,SKIP:duplicate-symbol:GMTC— never vague.Resolve owner wallet (env wins; otherwise read ONLY the labeled
## Owner Walletsection, never elsewhere in the file):if [[ -n "${OWNER_WALLET:-}" ]]; then OWNER="$OWNER_WALLET" else # Extract the section delimited by "## Owner Wallet" to the next "## " header, # then take the first 0x address inside that range. This pins fee routing to # the maintainer-pinned address — not any 0x that happens to appear above. OWNER=$(awk "/^## Owner Wallet[[:space:]]*$/{flag=1; next} /^## /{flag=0} flag" memory/watched-repos.md 2>/dev/null | grep -oE "0x[a-fA-F0-9]{40}" | head -1) fi if [[ -z "${OWNER:-}" ]]; then echo "SKIP:no-owner-wallet"; exit 0 fi if ! [[ "$OWNER" =~ ^0x[a-fA-F0-9]{40}$ ]]; then echo "SKIP:invalid-owner-wallet"; exit 0 fiBuild the deploy payload as a structured request file. The postprocess shim consumes this:
mkdir -p .pending-liquidpad REQ_ID="$(date -u +%Y%m%dT%H%M%SZ)-${SYMBOL}" jq -n \ --arg endpoint "/agent/run-once" \ --arg name "$NAME" \ --arg symbol "$SYMBOL" \ --arg theme "$THEME" \ --arg owner "$OWNER" \ --argjson mc "${MC_ETH:-5}" \ '{ endpoint: $endpoint, payload: { ownerAddress: $owner, name: $name, symbol: $symbol, theme: $theme, mcEth: $mc, withImage: true, runImmediately: false } }' > ".pending-liquidpad/${REQ_ID}.json"The skill is done at this point. It does NOT call the API.
Persist state — append the launch entry to
memory/topics/liquidpad-state.json:{ "ts": "2026-05-25T14:30:00Z", "symbol": "GMTC", "name": "Ghost Matcha", "req_id": "20260525T143000Z-GMTC", "owner": "0xWallet..." }Validate with
jq empty; restore.bakon failure.Log to memory/logs/${today}.md under a
### liquidpad-launchheading:Mode: live | dry-run (readLIQUIDPAD_DRY_RUNenv)Concept source: var | cache | derivedResult: emitted<req_id>| skipped:<reason>Owner: 0xWallet... (last 4 chars only)Symbol: GMTCNote: postprocess shim will execute the deploy and write.liquidpad-cache/<req_id>.result.json
Reading the deploy result on the next run
The postprocess shim writes a result file at .liquidpad-cache/<req_id>.result.json. The next time the skill runs, it should pick up any new result files and:
for r in .liquidpad-cache/*.result.json; do
[ -f "$r" ] || continue
HTTP=$(jq -r '.http_code' "$r")
REQ=$(jq -r '.req_id' "$r")
if [ "$HTTP" = "200" ]; then
ADDR=$(jq -r '.body.token.address // .body.address // empty' "$r")
TX=$(jq -r '.body.txHash // .body.tx // empty' "$r")
# Notify success — but only once per req_id
# ...
else
# Notify failure with HTTP code
# ...
fi
# Move to memory archive so we don't re-notify
mkdir -p memory/topics/liquidpad-results
mv "$r" memory/topics/liquidpad-results/
doneThis keeps the success/failure notification idempotent across runs — the skill notifies exactly once per req_id, then archives.
Constraints
- Never emit a payload with
ownerAddressset to a placeholder, the LiquidPad operator address, or any wallet not explicitly resolved from env or memory. - Never call
api.liquidpad.sitedirectly from the skill body — the sandbox blocks it and the shim split is the only correct path. - Never re-emit the same
symbolwithin 24h, even if the previous attempt failed — duplicate symbols on Uniswap V4 cause user confusion. - Never emit more than
MAX_LAUNCHES_PER_DAYpayloads per skill invocation. - Never persist
LIQUIDPAD_API_KEYto memory or logs. The skill body never sees it.
Running this as part of the agent loop
To make autonomous-launch part of the agent's daily routine, add a ## Daily Routine entry that invokes this skill conditionally — e.g. only on Mondays, only when memory/topics/concept-queue.md has unshipped entries. The daily cap (default 1) protects against runaway behavior; raise it via MAX_LAUNCHES_PER_DAY only after observing safe behavior.
Workflow integration
Add to the agent's workflow YAML:
- name: Prefetch LiquidPad context
run: ./scripts/prefetch-liquidpad.sh liquidpad-launch "${{ inputs.var }}"
env:
LIQUIDPAD_API_KEY: ${{ secrets.LIQUIDPAD_API_KEY }}
- name: Run agent (skill executes here, in sandbox)
# ... your usual agent step ...
- name: Postprocess LiquidPad deploys
run: ./scripts/postprocess-liquidpad.sh
env:
LIQUIDPAD_API_KEY: ${{ secrets.LIQUIDPAD_API_KEY }}
# LIQUIDPAD_DRY_RUN: "1" # uncomment to test without deployingReference
- LiquidPad public API:
https://api.liquidpad.site(health, agent/status, agent/run-once, verify, agent/concept) - Skill manifest (LLM-readable):
https://www.liquidpad.site/agent-owner-launch-skill.md - ERC-8004 agent record:
https://8004agents.ai/base/agent/50962 - Ecosystem attribution + live contributions:
https://www.liquidpad.site/ecosystem - Telegram operator interface:
@liquidpadbot(/setaddress,/apikey,/fast Name SYMBOL,/ai <prompt>)