Docs

Two functions and you are automated. Prefer an agent-driven flow? The complete zero-config rulefile (interface, rules, Foundry test template, deploy scripts) is downloadable: SKILL.md - drop it into .cursor/rules/, .claude/skills/, or your repo root.

1. Implement IAutoJob

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface IAutoJob {
    /// @dev MUST NOT mutate state. Returns true only when performJob is ready.
    function checkJob() external view returns (bool canExec, bytes memory execPayload);

    /// @dev MUST be restricted to the PeekRegistry. MUST flip checkJob to
    ///      false for the next block.
    function performJob(bytes calldata execPayload) external;
}

Rules that matter: checkJob is view-only and cheap; performJob is restricted to the registry, writes its "already done" state BEFORE external calls, and is idempotent so a retry can never double-execute.

2. Or write a thin adapter

Reference pattern for ve(3,3) epoch maintenance (Pharaoh-style voter.distribute() / gauge.harvest()):

contract EpochKeeper is IAutoJob {
    address public immutable REGISTRY_ADDRESS;
    IVoter public immutable voter;
    uint256 public nextEpoch;

    error NotRegistry();

    constructor(address registry, address voter_, uint256 firstEpoch) {
        REGISTRY_ADDRESS = registry;
        voter = IVoter(voter_);
        nextEpoch = firstEpoch;
    }

    function checkJob() external view returns (bool, bytes memory) {
        return (block.timestamp >= nextEpoch, "");
    }

    function performJob(bytes calldata) external {
        if (msg.sender != REGISTRY_ADDRESS) revert NotRegistry();
        uint256 ts = nextEpoch;
        if (block.timestamp < ts) return;      // idempotent within an epoch
        nextEpoch = ts + 1 weeks;              // effect first
        bool ok;
        try voter.distribute() {
            ok = true;   // recorded; a failed leg retries next epoch
        } catch {
            ok = false;  // never roll back the epoch
        }
    }
}

3. Register and fund

# register with a 0.2 AVAX escrow via the CLI
peekpeak register 43113 0xYourKeeper \
  --gas-limit 500000 --max-gas-price-gwei 100 \
  --deposit-wei 200000000000000000 --keystore executor.json

# or with Foundry
DEPLOYER_KEY=0x.. REGISTRY=0x.. TARGET=0x.. GAS_LIMIT=500000 \
MAX_GAS_PRICE_GWEI=100 DEPOSIT_WEI=200000000000000000 \
forge script script/RegisterJob.s.sol:RegisterJob \
  --rpc-url $FUJI_RPC --broadcast

Ship the three required Foundry tests (state flip, mock-registry execution, non-registry revert) - the templates are in SKILL.md.

Registry API

CallWhoEffect
registerJob(target, gasLimit, maxGasPriceGwei) payableyoucreates the job, funds escrow
depositGas(jobId) payableanyonetops up escrow
withdrawGas(jobId, amount)job ownerdrains escrow
setJobStatus(jobId, bool)job ownerpause / resume
executeJob(jobId, payload)authorized executor onlyruns performJob; charges escrow exactly gasUsed x gasPrice + 0.005 AVAX flat tip

A reverting performJob never charges your escrow; three consecutive reverts auto-deactivate the job.

Going further