<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jakhongir Tashpulatov</title>
    <description>The latest articles on DEV Community by Jakhongir Tashpulatov (@bczak).</description>
    <link>https://dev.to/bczak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4174971%2F9648a28a-a436-460b-a6ae-bcad862096de.png</url>
      <title>DEV Community: Jakhongir Tashpulatov</title>
      <link>https://dev.to/bczak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bczak"/>
    <language>en</language>
    <item>
      <title>Gelato Web3 Functions shut down. Here's how to port yours</title>
      <dc:creator>Jakhongir Tashpulatov</dc:creator>
      <pubDate>Mon, 19 Oct 2026 08:45:37 +0000</pubDate>
      <link>https://dev.to/thymelabs/gelato-web3-functions-shut-down-heres-how-to-port-yours-14i0</link>
      <guid>https://dev.to/thymelabs/gelato-web3-functions-shut-down-heres-how-to-port-yours-14i0</guid>
      <description>&lt;p&gt;Gelato ended Web3 Functions and Automate on &lt;strong&gt;March 31, 2026&lt;/strong&gt;. Every task created there stopped: the triggers, the recurring jobs, the logs. If a contract of yours depended on one, it has been waiting for an executor since spring.&lt;/p&gt;

&lt;p&gt;We run &lt;a href="https://flow.thymelabs.io" rel="noopener noreferrer"&gt;Thyme Flow&lt;/a&gt;, which does the same kind of job: a TypeScript function that reads the chain, decides, and returns the calls to send. This post shows a real port, the few places where things differ, and how to hand the whole job to a coding agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Your decision logic does not change. Three things do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The entry point: &lt;code&gt;Web3Function.onRun(...)&lt;/code&gt; becomes &lt;code&gt;defineTask({ schema, run })&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The provider: ethers via &lt;code&gt;multiChainProvider&lt;/code&gt; becomes &lt;code&gt;ctx.client&lt;/code&gt;, a read-only viem client.&lt;/li&gt;
&lt;li&gt;One field name: &lt;code&gt;callData&lt;/code&gt; becomes &lt;code&gt;calls&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;{ canExec: false, message }&lt;/code&gt; stays exactly as it was.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before: a Gelato oracle function
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Web3Function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Web3FunctionContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@gelatonetwork/web3-functions-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Contract&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ethersproject/contracts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ORACLE_ABI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function lastUpdated() view returns (uint256)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function updatePrice(uint256)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;Web3Function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onRun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Web3FunctionContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;multiChainProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secrets&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;multiChainProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oracle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oracle&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ORACLE_ABI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastUpdated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;oracle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lastUpdated&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;lastUpdated&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;canExec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Time not elapsed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PRICE_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;canExec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;callData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oracle&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;oracle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeFunctionData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;updatePrice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  After: the same function on Thyme Flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@thyme-labs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;encodeFunctionData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parseAbi&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseAbi&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function lastUpdated() view returns (uint256)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function updatePrice(uint256)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;oracle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastUpdated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oracle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lastUpdated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastUpdated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;canExec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Time not elapsed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PRICE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;canExec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oracle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;encodeFunctionData&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="nx"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;updatePrice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same check, same API call, same call returned. The arguments are now validated by a Zod schema before &lt;code&gt;run&lt;/code&gt; starts, and the console renders a form from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping the rest
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gelato&lt;/th&gt;
&lt;th&gt;Thyme Flow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;userArgs&lt;/code&gt; + &lt;code&gt;schema.json&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ctx.args&lt;/code&gt;, typed by Zod&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;await storage.get(key)&lt;/code&gt; / &lt;code&gt;storage.set(key, value)&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ctx.storage.key = value&lt;/code&gt; (plain JSON, not only strings)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;await secrets.get('KEY')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ctx.secrets.KEY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;npx w3f test&lt;/code&gt; with &lt;code&gt;userArgs.json&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;thyme run &amp;lt;task&amp;gt;&lt;/code&gt; with &lt;code&gt;args.json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;npx w3f deploy&lt;/code&gt;, then create a task from the CID&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;thyme upload &amp;lt;task&amp;gt; --tag v1&lt;/code&gt;, then create an executable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time interval and cron triggers&lt;/td&gt;
&lt;td&gt;Interval (30 seconds to one day) and cron&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-chain event or every-block triggers&lt;/td&gt;
&lt;td&gt;An interval that polls, with a block cursor in &lt;code&gt;ctx.storage&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dedicated msg.sender&lt;/td&gt;
&lt;td&gt;Your own Safe, through a role limited to the calls you allow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Where it is different
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Calls come from a Safe you own.&lt;/strong&gt; Gelato sent calls from its dedicated msg.sender. Flow sends them through a Zodiac Roles role on your Safe, limited to the contracts and functions you approve. Remove the role and access is gone. If your contract only accepted Gelato's sender, allow the Safe instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No event or block triggers.&lt;/strong&gt; Poll on a short interval and return &lt;code&gt;canExec: false&lt;/code&gt; when there is nothing new. Skipped runs send nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gas in USD.&lt;/strong&gt; Mainnet gas is sponsored and charged to a prepaid USD balance. Testnet gas is free.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Let your coding agent do it
&lt;/h2&gt;

&lt;p&gt;If you use Claude Code, Codex, Cursor or a similar agent, paste this into it from the repository that holds your Gelato functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read https://flow.thymelabs.io/docs/skills/thyme-migrate-gelato/SKILL.md and follow it to port the Gelato Web3 Functions in this repository to Thyme Flow. If you support skills, save that file as a skill named thyme-migrate-gelato. Start by listing the functions and triggers you find, port one, run it locally, and ask me before uploading or scheduling anything.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill tells the agent to inventory first, port one function at a time, test each locally, and stop on anything that needs you: a contract that only accepts Gelato, fee transfers to Gelato, calls that send ETH, or a chain that is not enabled. Login approval and Safe permissions always stay with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coming from Chainlink Automation instead?
&lt;/h2&gt;

&lt;p&gt;Chainlink retired Automation v2.1 on July 31, 2026. If your contract implements &lt;code&gt;checkUpkeep&lt;/code&gt; and &lt;code&gt;performUpkeep&lt;/code&gt;, one small task can call them unchanged. The guide is here: &lt;a href="https://flow.thymelabs.io/migrate/chainlink-automation" rel="noopener noreferrer"&gt;Chainlink Automation to Thyme Flow&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Full guide with the step list: &lt;a href="https://flow.thymelabs.io/migrate/gelato-web3-functions" rel="noopener noreferrer"&gt;Gelato Web3 Functions to Thyme Flow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SDK and CLI (MIT): &lt;a href="https://github.com/thyme-labs/sdk" rel="noopener noreferrer"&gt;github.com/thyme-labs/sdk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://flow.thymelabs.io/docs" rel="noopener noreferrer"&gt;flow.thymelabs.io/docs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stuck on a port? Send the function to &lt;a href="mailto:support@thymelabs.io"&gt;support@thymelabs.io&lt;/a&gt; and we'll help you move it.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>typescript</category>
      <category>automation</category>
    </item>
    <item>
      <title>Meet Thyme Gate</title>
      <dc:creator>Jakhongir Tashpulatov</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:45:56 +0000</pubDate>
      <link>https://dev.to/thymelabs/meet-thyme-gate-5eda</link>
      <guid>https://dev.to/thymelabs/meet-thyme-gate-5eda</guid>
      <description>&lt;p&gt;Every onchain app needs an RPC endpoint. Usually that's yet another vendor with its own dashboard, its own keys and its own bill, separate from the rest of your backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://gate.thymelabs.io" rel="noopener noreferrer"&gt;Thyme Gate&lt;/a&gt;&lt;/strong&gt; is the RPC product in &lt;a href="https://thymelabs.io" rel="noopener noreferrer"&gt;thyme/labs&lt;/a&gt;. It gives you a JSON-RPC endpoint per chain, with keys scoped to your project and usage you can actually read. It sits in the same workspace as our onchain automation (Flow) and hosted subgraphs (Atlas).&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep your client, change the URL
&lt;/h2&gt;

&lt;p&gt;There's no custom SDK or transport. If your code speaks JSON-RPC, it works with Gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a key
&lt;/h3&gt;

&lt;p&gt;Keys belong to a project. Name one for each app or environment, such as &lt;code&gt;orders-production&lt;/code&gt; or &lt;code&gt;orders-staging&lt;/code&gt;, so you can see each one's traffic and revoke them separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Choose a network
&lt;/h3&gt;

&lt;p&gt;Pick a mainnet or testnet. The console shows the exact HTTPS URL for every network available to your key.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Send a request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GATE_RPC_URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with viem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPublicClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mainnet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem/chains&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createPublicClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mainnet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GATE_RPC_URL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBlockNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reads, logs and transaction submissions all go through the same interface. To switch chains, change the endpoint and the chain config.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supported networks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Chain&lt;/th&gt;
&lt;th&gt;Chain ID&lt;/th&gt;
&lt;th&gt;Networks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Mainnet, Sepolia&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon&lt;/td&gt;
&lt;td&gt;137&lt;/td&gt;
&lt;td&gt;Mainnet, Amoy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimism&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Mainnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BNB Smart Chain&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;td&gt;Mainnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unichain&lt;/td&gt;
&lt;td&gt;1301&lt;/td&gt;
&lt;td&gt;Sepolia&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Need another chain? Email &lt;a href="mailto:support@thymelabs.io"&gt;support@thymelabs.io&lt;/a&gt; and tell us which one.&lt;/p&gt;

&lt;h2&gt;
  
  
  See the traffic behind the bill
&lt;/h2&gt;

&lt;p&gt;RPC bills are often a black box. Gate's console shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Requests and errors&lt;/strong&gt; by network&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute units by RPC method&lt;/strong&gt;, so you can see what's driving cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traffic and last use&lt;/strong&gt; per API key&lt;/li&gt;
&lt;li&gt;Your &lt;strong&gt;free allowance&lt;/strong&gt; through the billing cycle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If one method is eating your budget, you'll see it in the method breakdown instead of finding out on the invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keys you control
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keys are scoped to a project, and only workspace owners and admins can create or revoke them.&lt;/li&gt;
&lt;li&gt;To rotate a key without downtime, create a new one, deploy the new URL, check that traffic moved, then revoke the old key.&lt;/li&gt;
&lt;li&gt;Revoking a key stops future requests that use it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One tip: the endpoint URL contains your key. Keep it in server-side config, not in a browser bundle, and redact it from logs and screenshots.&lt;/p&gt;

&lt;p&gt;Need more throughput or a signed SLA? &lt;a href="mailto:support@thymelabs.io?subject=Thyme%20Gate%20Enterprise"&gt;Talk to us about enterprise&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Get an endpoint: &lt;a href="https://gate.thymelabs.io" rel="noopener noreferrer"&gt;https://gate.thymelabs.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Quickstart: &lt;a href="https://flow.thymelabs.io/docs/gate/quickstart" rel="noopener noreferrer"&gt;https://flow.thymelabs.io/docs/gate/quickstart&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your client is ready. Give it an endpoint. What are you building? Tell us in the comments. 👇&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>rpc</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>Meet Thyme Atlas</title>
      <dc:creator>Jakhongir Tashpulatov</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:43:46 +0000</pubDate>
      <link>https://dev.to/thymelabs/meet-thyme-atlas-5219</link>
      <guid>https://dev.to/thymelabs/meet-thyme-atlas-5219</guid>
      <description>&lt;p&gt;If your app shows onchain data like balances, positions, trade history or vault TVL, you've probably either scanned blocks yourself or run a Graph Node. Both mean babysitting infrastructure instead of shipping features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://atlas.thymelabs.io" rel="noopener noreferrer"&gt;Thyme Atlas&lt;/a&gt;&lt;/strong&gt; hosts your subgraphs. You deploy with the Graph CLI you already use, Atlas indexes your contracts on managed Graph Nodes, and you query decoded events and entity state over GraphQL. There's no node to run and no instance to size.&lt;/p&gt;

&lt;p&gt;Atlas is part of &lt;a href="https://thymelabs.io" rel="noopener noreferrer"&gt;thyme/labs&lt;/a&gt;, in the same workspace as our RPC (Gate) and onchain automation (Flow).&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the Graph CLI, change the node
&lt;/h2&gt;

&lt;p&gt;Your &lt;code&gt;subgraph.yaml&lt;/code&gt;, schema and mappings stay as they are. Atlas accepts the same build and IPFS upload that &lt;code&gt;graph-cli&lt;/code&gt; already produces.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create a subgraph
&lt;/h3&gt;

&lt;p&gt;Name it in the console. It lives in a project, with the same members and billing as the rest of your workspace.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create a deploy key
&lt;/h3&gt;

&lt;p&gt;Deploy keys belong to the project. The secret is shown once, and revoking a key stops new deploys within seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Run &lt;code&gt;graph deploy&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;graph codegen &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; graph build

graph deploy my-subgraph &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--node&lt;/span&gt; https://deploy.atlas.thymelabs.io/ &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ipfs&lt;/span&gt; https://ipfs.atlas.thymelabs.io/api/v0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--deploy-key&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ATLAS_DEPLOY_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--headers&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Authorization&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Bearer &lt;/span&gt;&lt;span class="nv"&gt;$ATLAS_DEPLOY_KEY&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version-label&lt;/span&gt; v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That uploads the build, creates a release and starts indexing.&lt;/p&gt;

&lt;h2&gt;
  
  
  One endpoint, keys you control
&lt;/h2&gt;

&lt;p&gt;Every subgraph gets an HTTPS GraphQL endpoint. It works with Graph Client, Apollo, urql or plain &lt;code&gt;fetch&lt;/code&gt;. Send a query key as a bearer token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ATLAS_QUERY_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ATLAS_QUERY_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{ vaults(first: 5) { id tvl } }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can scope a query key to a whole project or to a single subgraph.&lt;/li&gt;
&lt;li&gt;Revoked keys stop working within seconds.&lt;/li&gt;
&lt;li&gt;Every release has a GraphiQL playground, so you can test queries before you write code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ship the next version without downtime
&lt;/h2&gt;

&lt;p&gt;Re-indexing usually means downtime or juggling two endpoints. In Atlas, each deploy is an &lt;strong&gt;immutable release&lt;/strong&gt; that indexes alongside production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can follow indexing progress, health and errors for each release.&lt;/li&gt;
&lt;li&gt;Once the new release has caught up, promote it. Your production endpoint switches to it.&lt;/li&gt;
&lt;li&gt;If something looks wrong, roll back to the previous release in seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your app keeps querying the same URL the whole time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supported networks
&lt;/h2&gt;

&lt;p&gt;Atlas indexes these chains from nodes we run ourselves. In &lt;code&gt;subgraph.yaml&lt;/code&gt;, set the network to the name Graph Node expects:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Network&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;network:&lt;/code&gt; value&lt;/th&gt;
&lt;th&gt;Chain ID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mainnet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum Sepolia&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sepolia&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;11155111&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon&lt;/td&gt;
&lt;td&gt;&lt;code&gt;matic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;137&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon Amoy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;polygon-amoy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;80002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimism&lt;/td&gt;
&lt;td&gt;&lt;code&gt;optimism&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BNB Smart Chain&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bsc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unichain Sepolia&lt;/td&gt;
&lt;td&gt;&lt;code&gt;unichain-testnet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1301&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Need another chain? Email &lt;a href="mailto:support@thymelabs.io"&gt;support@thymelabs.io&lt;/a&gt; and tell us which one.&lt;/p&gt;

&lt;p&gt;Indexing a large protocol or need dedicated capacity? &lt;a href="mailto:support@thymelabs.io?subject=Thyme%20Atlas%20Enterprise"&gt;Talk to us about enterprise&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Deploy a subgraph: &lt;a href="https://atlas.thymelabs.io" rel="noopener noreferrer"&gt;https://atlas.thymelabs.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bring the subgraph, and we'll run the node. Got a subgraph you'd like to move over? Tell us in the comments. 👇&lt;/p&gt;

</description>
      <category>web3</category>
      <category>graphql</category>
      <category>subgraph</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Meet Thyme Flow</title>
      <dc:creator>Jakhongir Tashpulatov</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:34:34 +0000</pubDate>
      <link>https://dev.to/thymelabs/meet-thymelabs-rpc-subgraphs-on-chain-automation-and-gas-sponsorship-in-one-workspace-3a95</link>
      <guid>https://dev.to/thymelabs/meet-thymelabs-rpc-subgraphs-on-chain-automation-and-gas-sponsorship-in-one-workspace-3a95</guid>
      <description>&lt;p&gt;A lot of onchain apps need something to happen on a clock: harvest rewards, rebalance a vault, top up a balance, close an expired position. The usual options are a cron box holding a hot private key, or a keeper network you have to fund and trust with your contracts.&lt;/p&gt;

&lt;p&gt;We built &lt;strong&gt;&lt;a href="https://flow.thymelabs.io" rel="noopener noreferrer"&gt;Thyme Flow&lt;/a&gt;&lt;/strong&gt; so you don't have to pick either. You write a TypeScript task that decides what to do. Flow runs it on a schedule and sends the calls from &lt;strong&gt;a Safe you own&lt;/strong&gt;, through a role you can revoke whenever you want. We never hold the keys to your account.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Write a task
&lt;/h3&gt;

&lt;p&gt;A task is plain TypeScript. It reads live chain state and returns the calls to send, or decides to skip this run. You never sign anything in your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@thyme-labs/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;encodeFunctionData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parseAbi&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseAbi&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function harvest()&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function pendingRewards() view returns (uint256)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;minRewards&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coerce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;minRewards&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pendingRewards&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// Skip this run: not worth the gas yet.&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;minRewards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;canExec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; pending`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;canExec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;encodeFunctionData&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;harvest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The task context gives you what you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ctx.args&lt;/code&gt;&lt;/strong&gt;: typed inputs, validated against your Zod schema&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ctx.client&lt;/code&gt;&lt;/strong&gt;: a viem client for chain reads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ctx.secrets&lt;/code&gt;&lt;/strong&gt;: only the project secrets bound to this executable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ctx.storage&lt;/code&gt;&lt;/strong&gt;: JSON state that persists between runs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A run that returns &lt;code&gt;canExec: false&lt;/code&gt; sends no transaction. One run can return up to 32 calls, which are executed atomically in one transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Run it locally
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @thyme-labs/cli
thyme init my-automation
thyme run harvest-rewards &lt;span class="nt"&gt;--simulate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI runs your task in a local sandbox and simulates the returned calls against a real RPC. Nothing is signed or broadcast.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Upload it
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;thyme upload harvest-rewards &lt;span class="nt"&gt;--tag&lt;/span&gt; v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This bundles the task into an immutable, checksummed release. A tag can't be overwritten, so you always know which code is running.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Schedule it
&lt;/h3&gt;

&lt;p&gt;In the console, create an executable. You pick the Safe it runs from, its arguments and secrets, and when it runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cron&lt;/strong&gt;: any standard cron expression. The console reads it back in plain words before you save.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interval&lt;/strong&gt;: from every 30 seconds up to once a day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook&lt;/strong&gt;: up to ten named, secret URLs per executable. Each request body is validated against your task's schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flow handles the schedule, the signing and the gas from there. Every run shows up in the execution logs, with its decision, calls and transaction hash.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it stays safe
&lt;/h2&gt;

&lt;p&gt;Automation that can move funds needs a tight trust model. Here's ours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your Safe stays yours
&lt;/h3&gt;

&lt;p&gt;Your wallet owns the Safe. Flow gets a scoped executor role through the &lt;a href="https://github.com/gnosisguild/zodiac-modifier-roles" rel="noopener noreferrer"&gt;Zodiac Roles&lt;/a&gt; module, and that role can only:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;call the &lt;strong&gt;contract addresses and functions you allowlist&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;send calls with &lt;strong&gt;zero native value&lt;/strong&gt;, and never &lt;code&gt;delegatecall&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The executor can't widen its own role or administer your Safe. Only you, as the owner, can approve a broader scope, and you sign that change yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Revoke any time
&lt;/h3&gt;

&lt;p&gt;Remove the role or the module from your Safe and Flow can't submit anything, ever. That's a normal Safe transaction, and it doesn't need our permission. Pausing an executable in the console stops runs too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check before you sign
&lt;/h3&gt;

&lt;p&gt;When you set up a Safe profile, the console checks the deployed contract code against pinned hashes before it asks for your signature.&lt;/p&gt;

&lt;p&gt;You don't have to take our word for it, either. &lt;code&gt;thyme verify roles-profile&lt;/code&gt; independently rebuilds the setup from pinned Safe and Zodiac Roles versions, then checks the signature request or the deployed contracts against the allowlist you intended. It never calls the Thyme API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Declare what your code may call
&lt;/h3&gt;

&lt;p&gt;A task can ship a &lt;code&gt;permissions.json&lt;/code&gt; that lists the contracts and functions it needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"calls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"arg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vault"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"harvest()"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flow checks that your Safe's role covers these calls before you can enable an executable. At runtime, any call outside the declaration is rejected before it's submitted. The manifest isn't a grant: only your signed Safe scope can give access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets stay out of your code
&lt;/h3&gt;

&lt;p&gt;Secrets live in a vault, not in your bundle. You bind each one to the executables that need it, and Flow redacts known secret values from logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Isolated runs
&lt;/h3&gt;

&lt;p&gt;Every cloud run executes in an isolated sandbox with a 30-second timeout. Each executable's storage is versioned and locked, so overlapping runs can't overwrite each other's state.&lt;/p&gt;

&lt;h3&gt;
  
  
  An honest caveat
&lt;/h3&gt;

&lt;p&gt;Roles scopes restrict the &lt;strong&gt;target contract and function&lt;/strong&gt;, not the arguments. If you allow &lt;code&gt;transfer&lt;/code&gt; or &lt;code&gt;approve&lt;/code&gt;, the task chooses the recipient and amount. Only allow functions you'd trust your task with, and keep only the funds the automation needs in the Safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Works with your coding agent
&lt;/h2&gt;

&lt;p&gt;Paste one prompt into Claude Code, Codex, Cursor or another coding agent, and it learns the &lt;code&gt;thyme&lt;/code&gt; CLI. It can write and test a task, upload it, create the executable, set the schedule and read run logs.&lt;/p&gt;

&lt;p&gt;Creating a Safe profile, or widening what it may call, still needs your signature in the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Start building: &lt;a href="https://flow.thymelabs.io" rel="noopener noreferrer"&gt;https://flow.thymelabs.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Quickstart: &lt;a href="https://flow.thymelabs.io/docs/getting-started/quickstart" rel="noopener noreferrer"&gt;https://flow.thymelabs.io/docs/getting-started/quickstart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SDK and CLI (open source, MIT): &lt;a href="https://github.com/thyme-labs/sdk" rel="noopener noreferrer"&gt;https://github.com/thyme-labs/sdk&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flow is part of &lt;a href="https://thymelabs.io" rel="noopener noreferrer"&gt;thyme/labs&lt;/a&gt;, which also offers RPC (Gate) and hosted subgraphs (Atlas) in the same workspace.&lt;/p&gt;

&lt;p&gt;What would you automate first? Tell us in the comments. 👇&lt;/p&gt;

</description>
      <category>web3</category>
      <category>ethereum</category>
      <category>blockchain</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
