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.

Deployed registries

Avalanche C-Chain
chainId 43114 · 0xb012fe01cd851c454bd5c7d20c3e3e3f98b4643d

1. Implement IAutoJob

IAutoJob.sol
// 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()):

EpochKeeper.sol
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 = 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

The paste-runnable walkthrough (deploy, register with the live registry, top up) lives on the start page - every command is copy-ready with the registry address prefilled.

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.

Running on your own L1

The same registry deploys on any Subnet-EVM Avalanche L1, escrowing in your chain's own gas token. Zero-tip mode, AVAX coverage terms for non-swappable tokens, and optional ICTT tip repatriation are specified in the repo (docs/l1-economics.md).