Skip to content

AgentOS 2026.8.13

Choose a tag to compare

@github-actions github-actions released this 13 Aug 08:37
· 460 commits to main since this release
512d9d1

A crypto-skill release. AgentOS can now launch a token on pools.fun and manage the creator fees afterwards, from a skill that keeps reading and signing in separate scripts and hashes the plan it quotes so the transaction that broadcasts is provably the one you approved.

Added

  • A bundled poolsdotfun-token-launcher skill. Launches a token through the pools.fun PartyFactory on Robinhood Chain (4663) and manages creator fees on the PartyLocker afterwards. There is no RPC to configure — the chain is fixed and the endpoint is built in, so the only thing to set is POOLSFUN_PRIVATE_KEY.

    • A launch is one irreversible transaction, and the skill says so before sending it. It CREATE2-deploys a fixed-supply ERC20 — 1,000,000,000 tokens, no owner, no mint function, no transfer hooks — opens a SushiSwap V3 pool at the 1% fee tier, and mints the entire supply as a single-sided full-range position whose LP NFT goes to the locker permanently. The launcher never holds the LP.

    • Reading and signing are separate scripts, not separate flags. pools_read.py quotes cost and opening price, inspects pool state, simulates a launch and mines a launch salt using only a --from address — it cannot sign even when the key is set. pools_write.py is the only script that can. A capability boundary that is a different file cannot be crossed by a mistyped argument.

    • The launch plan is hashed. What you were quoted and what gets broadcast are checked against each other, so a plan that renders one price and sends another does not exist as a state.

    • PINATA_JWT is optional and needed only to attach a token image. It is deliberately not declared in requires.env, because that field is a hard eligibility gate — listing it would have made the whole skill unavailable on any machine where a logo was never configured, including for the launches that do not want one.

  • The launcher finds a logo the user attached in chat. This took two passes to get right, and the first one was worse than nothing. Chat attachments exist in two shapes — inline base64 in the transcript for anything under ~2 MB, which is most logos, or staged content-addressed on disk under a sha256 name with no extension — and the skill originally scanned only the media directory and returned the newest file by mtime. In a live session that meant offering a three-day-old blob from an unrelated session as the token's logo: mtime cannot distinguish "the image the user just sent" from "some image", and a token's identity is immutable once the transaction lands.

    • The transcript is now the authority. Message rows carry their own timestamp and their session, so find-image reads both attachment shapes newest-message-first, materializes the bytes to a real file — the step that was missing, since the image was always available, just not anywhere --image could reach — and prints the exact launch --image … line. It flags any candidate older than 15 minutes or belonging to another session, and tells the agent to open the file and confirm before pinning it. The media-directory scan survives only as a hint when the transcript yields nothing, labelled as probably-not-it.

    • An empty result is an answer, not a failed search. When there is no image, the command says so and lists the alternatives in preference order — ask the user for a real path, use --metadata-uri for an already-hosted logo, or launch without one — noting that a logo cannot be added afterwards. The previous documentation claimed an attached image "lands on disk", which is what sent the agent hunting for a file that had never been written.

Security

Found and closed in review before the skill shipped:

  • A private key with one mistyped character was printed in full to stderr. Validation checked length and prefix and then let int(key, 16) raise — and ValueError embeds the offending string, which the top-level handler prints straight into the agent transcript. The alphabet is now validated first, and the error carries no key material.

  • The "To execute" replay line was command-injectable. It quoted values with double quotes, which do not neuter $(…) or backticks, so a token name — attacker-influenced text — of the form X$(cmd) produced a suggested command that ran cmd. Quoting now goes through shlex.quote.

  • A failed RPC read of the factory's paused switch was read as "not paused". read_factory_state maps a failed call to None, and if state["paused"] is false for None, so a hiccup could launch into a paused factory and burn the full ~6.1M gas. The guard now fails closed on an unknown switch and preflight reports "unknown" rather than "no".

  • Value-taking flags silently accepted their own absence. A bare --slippage-bps became int(True) == 1, so asking for looser slippage gave the tightest possible setting; --image with no value became a True sentinel that an isinstance check discarded, silently launching an image-less token against a contract the docs state three times. opt_str/opt_int/opt_float are now the single place that sentinel is rejected. --slippage-bps is also clamped to 0…9999, since a negative value set devBuyMinOut above the exact simulated fill and produced a plan that hashed normally and then reverted on-chain.

  • Three error-message selectors were wrong, and one of them reported ZeroAmount() as "your dev buy is too large". The table is now keyed by signature with selectors computed at import, which makes the class of bug impossible, and the selftest iterates the table rather than a hand-copied subset.

The skill ships with 200 offline self-test checks, pinning launch calldata byte-for-byte against a reference transaction, every custom error selector, plan-hash sensitivity, the Pinata-optional matrix, the capability separation, and the attachment-resolution behavior against a miniature sessions.db.


Full changelog: v2026.8.12...v2026.8.13