<?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: Gitroom</title>
    <description>The latest articles on DEV Community by Gitroom (@github20k).</description>
    <link>https://dev.to/github20k</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.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F6880%2Fa7d0629e-2df8-4705-af5a-7c0a226b6e0a.gif</url>
      <title>DEV Community: Gitroom</title>
      <link>https://dev.to/github20k</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/github20k"/>
    <language>en</language>
    <item>
      <title>The project I built with the Twitter API, GPT4 &amp; CopilotKit…🚀🧑‍💻</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Thu, 08 Aug 2024 10:58:53 +0000</pubDate>
      <link>https://dev.to/github20k/i-10xd-my-x-posts-using-the-twitter-api-openai-copilotkit-2d5n</link>
      <guid>https://dev.to/github20k/i-10xd-my-x-posts-using-the-twitter-api-openai-copilotkit-2d5n</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Last week I built an application that automates my social media posting using AI. I will show you how I did it. &lt;/p&gt;

&lt;p&gt;We will cover how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add Twitter authentication to a Next.js application,&lt;/li&gt;
&lt;li&gt;create a calendar-like interface from scratch,&lt;/li&gt;
&lt;li&gt;integrate AI assistants into software applications with CopilotKit,&lt;/li&gt;
&lt;li&gt;create action-specific AI copilots to handle various tasks within the application, and&lt;/li&gt;
&lt;li&gt;build a post generator and scheduling application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This project is a great way to learn how to build AI-powered apps and master social media APIs, but don't use it to be mean 😈&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5njscmuafgzhzgufcxh8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5njscmuafgzhzgufcxh8.gif" alt="It's a me, Elon" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  CopilotKit: The framework for building in-app AI copilots
&lt;/h2&gt;

&lt;p&gt;CopilotKit is an &lt;a href="https://github.com/CopilotKit/CopilotKit" rel="noopener noreferrer"&gt;open-source AI copilot platform&lt;/a&gt;. We make it easy to integrate powerful AI into your React apps.&lt;/p&gt;

&lt;p&gt;Build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ChatBot: Context-aware in-app chatbots that can take actions in-app 💬&lt;/li&gt;
&lt;li&gt;CopilotTextArea: AI-powered textFields with context-aware autocomplete &amp;amp; insertions 📝&lt;/li&gt;
&lt;li&gt;Co-Agents: In-app AI agents that can interact with your app &amp;amp; users 🤖&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8hgc7mc82s60na57ssz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8hgc7mc82s60na57ssz.gif" alt="Star CopilotKit" width="200" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.new/devtoarticle1" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Star CopilotKit ⭐️&lt;/a&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To fully understand this tutorial, you need to have a basic understanding of React or Next.js.&lt;/p&gt;

&lt;p&gt;We'll also make use of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/CopilotKit/CopilotKit" rel="noopener noreferrer"&gt;CopilotKit&lt;/a&gt; - an open-source copilot framework for building custom AI chatbots, in-app AI agents, and text areas.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/redis/ioredis#readme" rel="noopener noreferrer"&gt;Redis&lt;/a&gt; - an in-memory database for storing the post schedule.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.bullmq.io/" rel="noopener noreferrer"&gt;BullMQ&lt;/a&gt; - a Node.js library that manages and processes jobs in a queue.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/node-cron" rel="noopener noreferrer"&gt;Node Cron&lt;/a&gt; - a Node.js library that schedule and runs tasks (jobs) at specific intervals.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://headlessui.com/" rel="noopener noreferrer"&gt;Headless UI&lt;/a&gt; - for creating accessible UI components for the application.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.twitter.com/en/portal/dashboard" rel="noopener noreferrer"&gt;X Client ID and Secret&lt;/a&gt; - for authenticating users and creating posts on their behalf.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://platform.openai.com/api-keys" rel="noopener noreferrer"&gt;OpenAI API Key&lt;/a&gt; - to enable us to perform various tasks using the GPT models.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Project Set up and Package Installation
&lt;/h2&gt;

&lt;p&gt;First, create a Next.js application by running the code snippet below in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app social-media-scheduler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select your preferred configuration settings. For this tutorial, we'll be using TypeScript and Next.js App Router.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4k3424y719fsu7vuryq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4k3424y719fsu7vuryq.png" alt="Creating the Next.js application" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, install the project dependencies:&lt;br&gt;
&lt;/p&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; @headlessui/react lodash bullmq ioredis node-cron
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, install the required &lt;a href="https://docs.copilotkit.ai/getting-started/quickstart-chatbot" rel="noopener noreferrer"&gt;CopilotKit packages&lt;/a&gt;. These packages enable us to use AI auto-completion within the application, allow the AI copilot to retrieve data from the React state, and make decisions within the application.&lt;br&gt;
&lt;/p&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; @copilotkit/react-ui @copilotkit/react-textarea @copilotkit/react-core @copilotkit/backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! You're now ready to build the application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building the Posts Scheduler App with Next.js
&lt;/h2&gt;

&lt;p&gt;In this section, you'll learn how to create the user interface for the scheduling application. The application is divided into two pages: the Login page and the Dashboard page, where users can create and schedule posts.&lt;/p&gt;

&lt;p&gt;The Login page authenticates users using their X (Twitter) profile, while the Dashboard page allows users to create, delete, and schedule posts.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Login Page
&lt;/h3&gt;

&lt;p&gt;The Login page represents the application's home page. Users need to sign in with their Twitter account to access the dashboard.&lt;/p&gt;

&lt;p&gt;To implement this, update the &lt;code&gt;page.tsx&lt;/code&gt; file to display a sign-in button as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;getTwitterOauthUrl&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="s2"&gt;@/app/util&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'w-full min-h-screen flex flex-col items-center justify-center p-8'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'font-semibold text-2xl mb-4'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Your AI Post Scheduler&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;
                &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;getTwitterOauthUrl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'bg-black py-3 px-6 hover:bg-gray-700 text-gray-50 rounded-lg'&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                Sign in with Twitter
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;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 code snippet above displays a &lt;code&gt;Sign in with Twitter&lt;/code&gt; button that redirects users to Twitter Oauth2 page. You'll learn how to setup the Twitter authentication shortly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujy54u1xelubytvrtut6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujy54u1xelubytvrtut6.png" alt="Login Button" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Dashboard Page
&lt;/h3&gt;

&lt;p&gt;Before we proceed, create a &lt;code&gt;types.d.ts&lt;/code&gt; file at the root of the Next.js project. This file will contain the type declarations for the variables within the application.&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;DelSelectedCell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;day_id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;day&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;time_id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;time&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;published&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SelectedCell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;day_id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;day&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;time_id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;time&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;published&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;day&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AvailableScheduleItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Content&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;Create a &lt;code&gt;utils&lt;/code&gt; file within the Next.js app folder and copy &lt;a href="https://github.com/dha-stix/ai-post-generator-and-scheduler-with-copilotkit/blob/main/src/app/util.ts" rel="noopener noreferrer"&gt;this code snippet from the GitHub repository&lt;/a&gt; into it. It contains the necessary functions for performing various data manipulations within the application.&lt;/p&gt;

&lt;p&gt;Next, create a &lt;code&gt;dashboard&lt;/code&gt; folder containing a &lt;code&gt;page.tsx&lt;/code&gt; file within the Next.js app directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;app
&lt;span class="nb"&gt;mkdir &lt;/span&gt;dashboard &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;dashboard
&lt;span class="nb"&gt;touch &lt;/span&gt;page.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the code snippet below into the &lt;code&gt;dashboard/page.tsx&lt;/code&gt; file. It renders an &lt;code&gt;App&lt;/code&gt; component that accepts the application's schedule as props and displays them in a table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;useState&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="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/app/components/App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;availableSchedule&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="s2"&gt;../util&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//👇🏻 saves a deep copy of the availableSchedule array into the React state&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;yourSchedule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateYourSchedule&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AvailableScheduleItem&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="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;availableSchedule&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="na"&gt;yourSchedule&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;yourSchedule&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;updateYourSchedule&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;updateYourSchedule&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwo8vhvu2g3j8c28x92ax.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwo8vhvu2g3j8c28x92ax.gif" alt="Post Schedule" width="760" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the data structure for the table above:&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tableHeadings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&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="s2"&gt;Time&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="s2"&gt;Sunday&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="s2"&gt;Monday&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="s2"&gt;Tuesday&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="s2"&gt;Wednesday&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="s2"&gt;Thursday&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="s2"&gt;Friday&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="s2"&gt;Saturday&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;availableSchedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AvailableScheduleItem&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&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;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schedule&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;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 &lt;strong&gt;&lt;code&gt;tableHeadings&lt;/code&gt;&lt;/strong&gt; array contains the headings for the table columns, while the &lt;strong&gt;&lt;code&gt;availableSchedule&lt;/code&gt;&lt;/strong&gt; array holds a group of objects. Each object has a &lt;strong&gt;&lt;code&gt;time&lt;/code&gt;&lt;/strong&gt; property representing each hour of the day and a &lt;strong&gt;&lt;code&gt;schedule&lt;/code&gt;&lt;/strong&gt; property containing a nested array, with each element representing a day of the week. &lt;/p&gt;

&lt;p&gt;For example, when a user sets a schedule for Wednesday at 8 AM, the application searches for the object with a &lt;strong&gt;&lt;code&gt;time&lt;/code&gt;&lt;/strong&gt; property of 8 and updates its &lt;strong&gt;&lt;code&gt;schedule&lt;/code&gt;&lt;/strong&gt; property by inserting the schedule into the nested array at the fourth index.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Vn-tuKgqMp4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You can copy the remaining UI elements for the Dashboard page from its &lt;a href="https://github.com/dha-stix/ai-post-generator-and-scheduler-with-copilotkit/tree/main/src/app/components" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the upcoming sections, you'll learn how to add Twitter OAuth and CopilotKit to the application.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to add X Authentication to your Next.js application
&lt;/h2&gt;

&lt;p&gt;In this section, you’ll learn how to create a X Developer project and add X authentication your Next.js applications.&lt;/p&gt;

&lt;p&gt;Ensure you have an X account and visit the &lt;a href="https://developer.twitter.com/en/portal/dashboard" rel="noopener noreferrer"&gt;X Developers' Portal&lt;/a&gt; to create a new project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2e9sd4ftlv1rtz1c15xx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2e9sd4ftlv1rtz1c15xx.png" alt="Create X Developer Project" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the project name and provide answers to the required questions to create a new project and an app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0nyebp8ewf8qkhgnpmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0nyebp8ewf8qkhgnpmc.png" alt="X Developer Project" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set up the user authentication settings to allow you read and write posts on behalf of the users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7e2yyfw9pk24vudk3y4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7e2yyfw9pk24vudk3y4.png" alt="X Authentication Settings" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, fill the &lt;strong&gt;&lt;code&gt;App info&lt;/code&gt;&lt;/strong&gt; section accordingly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9hkgb8ozstyty5u6bca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9hkgb8ozstyty5u6bca.png" alt="X App Info section" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After setting up the authentication process, save the OAuth 2.0 Client ID and secret into a &lt;strong&gt;&lt;code&gt;.env.local&lt;/code&gt;&lt;/strong&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TWITTER_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your_client_ID&amp;gt;
&lt;span class="nv"&gt;NEXT_PUBLIC_TWITTER_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your_client_ID&amp;gt;
&lt;span class="nv"&gt;TWITTER_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your_client_Secret&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Authenticating users via X
&lt;/h3&gt;

&lt;p&gt;Create an &lt;strong&gt;&lt;code&gt;api&lt;/code&gt;&lt;/strong&gt; folder within the Next.js &lt;strong&gt;&lt;code&gt;app&lt;/code&gt;&lt;/strong&gt; folder. Inside the api folder, create a &lt;strong&gt;&lt;code&gt;twitter&lt;/code&gt;&lt;/strong&gt; directory containing a &lt;strong&gt;&lt;code&gt;route.ts&lt;/code&gt;&lt;/strong&gt; file. This will create an API endpoint (&lt;code&gt;/api/twitter&lt;/code&gt;) that enables us to authenticate users.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;app
&lt;span class="nb"&gt;mkdir &lt;/span&gt;api &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;api
&lt;span class="nb"&gt;mkdir &lt;/span&gt;twitter &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;twitter
&lt;span class="nb"&gt;touch &lt;/span&gt;route.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the code snippet below into the &lt;strong&gt;&lt;code&gt;route.ts&lt;/code&gt;&lt;/strong&gt; file:&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;NextRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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="s2"&gt;next/server&lt;/span&gt;&lt;span class="dl"&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;BasicAuthToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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;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;TWITTER_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;!&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;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;TWITTER_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&lt;/span&gt;&lt;span class="dl"&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;twitterOauthTokenParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;client_id&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;TWITTER_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;code_verifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8KxxO-RPl0bLSxX5AWwgdiFbMnry_VOKzFeIlVA7NoA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://www.localhost:3000/dashboard`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;grant_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authorization_code&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;//👇🏻 gets user access token&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchUserToken&lt;/span&gt; &lt;span class="o"&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;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="k"&gt;try&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;formatData&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;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;twitterOauthTokenParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;code&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;getTokenRequest&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.twitter.com/2/oauth2/token&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="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="s2"&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;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formatData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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="s2"&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="s2"&gt;application/x-www-form-urlencoded&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;`Basic &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BasicAuthToken&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="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;getTokenResponse&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;getTokenRequest&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;getTokenResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="kc"&gt;null&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="c1"&gt;//👇🏻gets user's data from the access token&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchUserData&lt;/span&gt; &lt;span class="o"&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;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="k"&gt;try&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;getUserRequest&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.twitter.com/2/users/me&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="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="s2"&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="s2"&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;accessToken&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="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUserProfile&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;getUserRequest&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;getUserProfile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="kc"&gt;null&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="c1"&gt;//👉🏻 API endpoint utilizing the functions above&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;From the code snippet above,

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;BasicAuthToken&lt;/code&gt; variable contains the encoded version of your tokens.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;twitterOauthTokenParams&lt;/code&gt; contains the parameters required for getting the users' access token.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;fetchUserToken&lt;/code&gt; function sends a request containing a code to Twitter's endpoint and returns the user's access token.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;fetchUserData&lt;/code&gt; function uses the token to retrieve the user's X profile.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Add this endpoint below the functions. It accepts a code from the frontend when a user signs in and stores the user ID, username, and access token in a file that can be accessed when executing jobs on the server.&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;writeFile&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="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&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;code&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;req&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;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//👇🏻 get access token and the entire response&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenResponse&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;fetchUserToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&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;accessToken&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;tokenResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;//👇🏻 get user data&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userDataResponse&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;fetchUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accessToken&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;userCredentials&lt;/span&gt; &lt;span class="o"&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;tokenResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;userDataResponse&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c1"&gt;//👇🏻  merge the user's access token, id, and username into an object&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userCredentials&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="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userCredentials&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="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="c1"&gt;//👇🏻 store them in a JSON file (for server-use)&lt;/span&gt;
        &lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/user.json&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;An error has occurred &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Data written successfully to disk&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;//👇🏻 returns a successful response&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User data stored successfully&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="nx"&gt;NextResponse&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;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;Update the &lt;strong&gt;&lt;code&gt;dashboard/page.tsx&lt;/code&gt;&lt;/strong&gt; to send the code to the API endpoint after authenticating a user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;useSearchParams&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;next/navigation&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;searchParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSearchParams&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;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchParams&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;code&lt;/span&gt;&lt;span class="dl"&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;fetchToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/twitter&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="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="s2"&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;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="nx"&gt;code&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="s2"&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="s2"&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="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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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;data&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;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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="p"&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;code&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="nf"&gt;useEffect&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="nf"&gt;fetchToken&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="nx"&gt;fetchToken&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! When users click the &lt;strong&gt;&lt;code&gt;Sign in with Twitter&lt;/code&gt;&lt;/strong&gt; button, it redirects them to the Twitter authorisation page to enable them access the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i1md2jf0uicg6ddt0x1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i1md2jf0uicg6ddt0x1.gif" alt="X Authentication Preview" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How to add CopilotKit to a Next.js application
&lt;/h2&gt;

&lt;p&gt;In this section, you'll learn how to add CopilotKit to the application to enable users to schedule posts automatically using AI copilots and also add auto-completion when creating post contents.&lt;/p&gt;

&lt;p&gt;Before we proceed, visit the &lt;a href="https://platform.openai.com/api-keys" rel="noopener noreferrer"&gt;OpenAI Developers' Platform&lt;/a&gt; and create a new secret key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Forhfk6mxep482gngw6g5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Forhfk6mxep482gngw6g5.png" alt="OpenAI API" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a &lt;strong&gt;&lt;code&gt;.env.local&lt;/code&gt;&lt;/strong&gt; file and copy the your newly created secret key into the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_OPENAI_SECRET_KEY&amp;gt;
&lt;span class="nv"&gt;OPENAI_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gpt-4-1106-preview
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you need to create an API endpoint for CopilotKit. Within the Next.js app folder, create an &lt;strong&gt;&lt;code&gt;api/copilotkit&lt;/code&gt;&lt;/strong&gt; folder containing a &lt;strong&gt;&lt;code&gt;route.ts&lt;/code&gt;&lt;/strong&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;app
&lt;span class="nb"&gt;mkdir &lt;/span&gt;api &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;api
&lt;span class="nb"&gt;mkdir &lt;/span&gt;copilotkit &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;copilotkit
&lt;span class="nb"&gt;touch &lt;/span&gt;route.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the code snippet below into the route.ts file. The &lt;a href="https://docs.copilotkit.ai/reference/CopilotBackend" rel="noopener noreferrer"&gt;CopilotKit backend&lt;/a&gt; accept users’ requests and make decisions using the OpenAI model.&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;CopilotRuntime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OpenAIAdapter&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="s2"&gt;@copilotkit/backend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;runtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edge&lt;/span&gt;&lt;span class="dl"&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Response&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="nx"&gt;copilotKit&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;CopilotRuntime&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;openaiModel&lt;/span&gt; &lt;span class="o"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPENAI_MODEL&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="nx"&gt;copilotKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAIAdapter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;openaiModel&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;To connect the application to the backend API route, copy the code snippet below into the &lt;strong&gt;&lt;code&gt;dashboard/page.tsx&lt;/code&gt;&lt;/strong&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/app/components/App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;useState&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="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;availableSchedule&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="s2"&gt;../util&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//👇🏻 CopilotKit components&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;CopilotKit&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="s2"&gt;@copilotkit/react-core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;CopilotPopup&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="s2"&gt;@copilotkit/react-ui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//👇🏻 CSS styles for CopilotKit components&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@copilotkit/react-ui/styles.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@copilotkit/react-textarea/styles.css&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&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;yourSchedule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateYourSchedule&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AvailableScheduleItem&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="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;availableSchedule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//👉🏻 other UI states and functions&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CopilotKit&lt;/span&gt; &lt;span class="na"&gt;runtimeUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'/api/copilotkit/'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;
                &lt;span class="na"&gt;yourSchedule&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;yourSchedule&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;updateYourSchedule&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;updateYourSchedule&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CopilotPopup&lt;/span&gt;
                &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'Help the user create and manage ad campaigns.'&lt;/span&gt;
                &lt;span class="na"&gt;defaultOpen&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Posts Scheduler Copilot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello there! I can help you manage your schedule. What do you want to do? You can generate posts, add, and delete scheduled posts.&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="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;clickOutsideToClose&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CopilotPopup&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CopilotKit&lt;/span&gt;&lt;span class="p"&gt;&amp;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 &lt;strong&gt;&lt;code&gt;CopilotKit&lt;/code&gt;&lt;/strong&gt; component wraps the entire application and accepts a &lt;strong&gt;&lt;code&gt;runtimeUrl&lt;/code&gt;&lt;/strong&gt; prop that contains a link to the API endpoint. The &lt;strong&gt;&lt;code&gt;CopilotKitPopup&lt;/code&gt;&lt;/strong&gt; component adds a chatbot sidebar panel to the application, enabling us to provide various instructions to CopilotKit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxft83wl1ws8vw0ec2rtc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxft83wl1ws8vw0ec2rtc.gif" alt="App Overview" width="760" height="423"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How to schedule posts with CopilotKit
&lt;/h2&gt;

&lt;p&gt;CopilotKit provides two hooks that enable us to handle user's request and plug into the application state: &lt;a href="https://docs.copilotkit.ai/reference/useCopilotAction" rel="noopener noreferrer"&gt;&lt;code&gt;useCopilotAction&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.copilotkit.ai/reference/hooks/useCopilotReadable" rel="noopener noreferrer"&gt;&lt;code&gt;useCopilotReadable&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;useCopilotAction&lt;/code&gt; hook allows you to define actions to be carried out by CopilotKit. It accepts an object containing the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name - the action's name.&lt;/li&gt;
&lt;li&gt;description - the action's description.&lt;/li&gt;
&lt;li&gt;parameters - an array containing the list of the required parameters.&lt;/li&gt;
&lt;li&gt;render - the default custom function or string.&lt;/li&gt;
&lt;li&gt;handler - the executable function that is triggered by the action.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useCopilotAction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sayHello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Say hello to someone.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;parameters&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name of the person to say greet&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="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Process greeting message...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;handler&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;name&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="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;&lt;code&gt;useCopilotReadable&lt;/code&gt;&lt;/strong&gt; hook provides the application state to CopilotKit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;useCopilotReadable&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="s2"&gt;@copilotkit/react-core&lt;/span&gt;&lt;span class="dl"&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;myAppState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;useCopilotReadable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The current state of the app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;myAppState&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s plug the application state into CopilotKit and create an action that helps us to schedule posts.&lt;/p&gt;

&lt;p&gt;Within the &lt;strong&gt;&lt;code&gt;App&lt;/code&gt;&lt;/strong&gt; component, pass the &lt;strong&gt;&lt;code&gt;schedule&lt;/code&gt;&lt;/strong&gt; state into CopilotKit. You can also provide additional information (context) to enable CopilotKit make adequate and precise decisions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;//👇🏻 Application state&lt;/span&gt;
&lt;span class="nf"&gt;useCopilotReadable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The user's Twitter post schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;yourSchedule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//👇🏻 Application context&lt;/span&gt;
&lt;span class="nf"&gt;useCopilotReadable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Guidelines for the user's Twitter post schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your schedule is displayed in a table format. Each row represents an hour of the day, and each column represents a day of the week. You can add a post by clicking on an empty cell, and delete a post by clicking on a filled cell. Sunday is the first day of the week and has a day_id of 0.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a CopilotKit action that schedule posts based on the user’s prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;    &lt;span class="nf"&gt;useCopilotAction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;updatePostSchedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Update the user's Twitter post schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;parameters&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;update_schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The user's updated post schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;attributes&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;time&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The time of the post&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object[]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The schedule for the time&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;attributes&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The content of the post&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;minutes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The minutes past the hour&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Whether the post is published&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;day&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The day of the week&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;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;update_schedule&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="nf"&gt;setAddEventModal&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="nf"&gt;setSelectedCell&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;day_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;update_schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tableHeadings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;update_schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;time_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;update_schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;formatTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;update_schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="nf"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;update_schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;setMinute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;update_schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Updating schedule...&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code snippet above shows the &lt;strong&gt;&lt;code&gt;useCopilotAction&lt;/code&gt;&lt;/strong&gt; hook in action. It accepts an object containing &lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;description&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;parameters&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;handler&lt;/code&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;code&gt;render&lt;/code&gt;&lt;/strong&gt; properties.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;name&lt;/code&gt;&lt;/strong&gt; property represents the name of the action.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;description&lt;/code&gt;&lt;/strong&gt; property provides a brief overview of what the function does.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;parameters&lt;/code&gt;&lt;/strong&gt; array contains an &lt;code&gt;update_schedule&lt;/code&gt; object with a &lt;strong&gt;&lt;code&gt;time&lt;/code&gt;&lt;/strong&gt; and &lt;code&gt;schedule&lt;/code&gt; property. The &lt;strong&gt;&lt;code&gt;schedule&lt;/code&gt;&lt;/strong&gt; object includes &lt;strong&gt;&lt;code&gt;content&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;minutes&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;published&lt;/code&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;code&gt;day&lt;/code&gt;&lt;/strong&gt; attributes.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;handler&lt;/code&gt;&lt;/strong&gt; function describes the action to be carried out when triggered. In the example above, the &lt;strong&gt;&lt;code&gt;handler&lt;/code&gt;&lt;/strong&gt; function opens the &lt;strong&gt;&lt;code&gt;AddPost&lt;/code&gt;&lt;/strong&gt; modal, updates its value with AI-generated inputs, and allows the user adjust the schedule accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ZJ7kcpfXyZc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing and Scheduling Posts using Redis and BullMQ
&lt;/h2&gt;

&lt;p&gt;In this section, you’ll learn how to store the post schedule in a Redis database, and create a job that checks the schedule at intervals to post the content on X (Twitter).&lt;/p&gt;

&lt;p&gt;First, you need to &lt;a href="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-mac-os/" rel="noopener noreferrer"&gt;install Redis on your computer&lt;/a&gt;. If you are using MacOS and have &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; installed, run the code snippet in your terminal to install Redis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nt"&gt;--version&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the installation process is complete, you can test your Redis server by running the following code snippet in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo84ve3nhqmgv5kfb38yw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo84ve3nhqmgv5kfb38yw.png" alt="Redis Server" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you can use the &lt;a href="https://www.npmjs.com/package/ioredis" rel="noopener noreferrer"&gt;Node.js Redis client&lt;/a&gt; within the application. &lt;/p&gt;

&lt;p&gt;Create an &lt;strong&gt;&lt;code&gt;/api/schedule&lt;/code&gt;&lt;/strong&gt; API route on the server that accepts the entire schedule table when a user adds or deletes a scheduled post.&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;NextRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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="s2"&gt;next/server&lt;/span&gt;&lt;span class="dl"&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&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;schedule&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;req&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;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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;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="s2"&gt;Schedule updated!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="nx"&gt;NextResponse&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;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="s2"&gt;Error updating schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;Update the API endpoint to store the entire schedule in the Redis database. Redis stores data in key/value pairs, making it super-fast for storing and retrieving data.&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;NextRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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="s2"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Redis&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ioredis&lt;/span&gt;&lt;span class="dl"&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;redis&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;Redis&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&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;schedule&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;req&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;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//👇🏻 saves the schedule&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schedule&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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;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="s2"&gt;Schedule updated!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="nx"&gt;NextResponse&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;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="s2"&gt;Error updating schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;You can also add a GET request handler within the &lt;strong&gt;&lt;code&gt;api/schedule/route.ts&lt;/code&gt;&lt;/strong&gt; file to fetch existing scheduled posts from the Redis database and display them when a user logs into the application.&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;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&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;schedule&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;redis&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="s2"&gt;schedule&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;schedule&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="nx"&gt;NextResponse&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;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="s2"&gt;Schedule found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;schedule&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schedule&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="nx"&gt;NextResponse&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;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="s2"&gt;Schedule not found&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;Finally, you need to set up a job queue that runs every minute to check for posts scheduled for the current day and post them at the appropriate time. &lt;/p&gt;

&lt;p&gt;Create a &lt;strong&gt;&lt;code&gt;worker.ts&lt;/code&gt;&lt;/strong&gt; file within the Next.js &lt;strong&gt;&lt;code&gt;src&lt;/code&gt;&lt;/strong&gt; folder and copy the following code into the file:&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="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./user.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;Worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Queue&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;bullmq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Redis&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ioredis&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//👇🏻 initializes a job queue connected to the Redis database&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redis&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;Redis&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;maxRetriesPerRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;scheduleQueue&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;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;schedule-queue&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="na"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code snippet above creates a job queue that is connected to the Redis database.&lt;/p&gt;

&lt;p&gt;Implement a &lt;strong&gt;&lt;code&gt;scheduleJobs&lt;/code&gt;&lt;/strong&gt; function within the &lt;strong&gt;&lt;code&gt;worker.ts&lt;/code&gt;&lt;/strong&gt; file that gets the posts scheduled for the current time and adds them to the job queue.&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="c1"&gt;//👇🏻 add jobs to the queue&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scheduleJobs&lt;/span&gt; &lt;span class="o"&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;schedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AvailableScheduleItem&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="c1"&gt;//👇🏻 gets current time and day&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&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;Date&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;currentHour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHours&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;currentMinute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMinutes&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;currentDay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;//👇🏻 gets posts for the current hour&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentSchedule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;currentHour&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;schedulesForTheHour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentSchedule&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currentDay&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;//👇🏻 gets scheduled posts for the current time&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;schedulesForTheHour&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;schedulesForTheHour&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&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;awaitingJobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;schedulesForTheHour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scheduleItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class="nx"&gt;scheduleItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;scheduleItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;currentMinute&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;//👇🏻 add jobs to queue&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;awaitingJobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&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;scheduleItem&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="nx"&gt;job&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;scheduleQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jobs&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;scheduleItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;removeOnComplete&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="p"&gt;});&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Job &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; added to queue`&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;Import the &lt;strong&gt;&lt;code&gt;scheduleJobs&lt;/code&gt;&lt;/strong&gt; function into the &lt;strong&gt;&lt;code&gt;api/schedule&lt;/code&gt;&lt;/strong&gt; endpoint and trigger the function every minute using Node Cron.&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="c1"&gt;//👉🏻 api/schedule/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cron&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node-cron&lt;/span&gt;&lt;span class="dl"&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&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;schedule&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;req&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;span class="k"&gt;try&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;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schedule&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nx"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* * * * *&lt;/span&gt;&lt;span class="dl"&gt;'&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Triggering jobs...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scheduleJobs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schedule&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="nx"&gt;NextResponse&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;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="s2"&gt;Schedule updated!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="nx"&gt;NextResponse&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;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="s2"&gt;Error updating schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;Next, add a &lt;a href="https://docs.bullmq.io/guide/workers" rel="noopener noreferrer"&gt;worker function&lt;/a&gt; within the &lt;strong&gt;&lt;code&gt;workers.ts&lt;/code&gt;&lt;/strong&gt; file that executes the jobs within the queue by sending the posts’ content to X (Twitter).&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="c1"&gt;//👇🏻 processing jobs&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scheduleWorker&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;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;schedule-queue&lt;/span&gt;&lt;span class="dl"&gt;'&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;job&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Processing job &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; of type &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; with data: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;job&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="nx"&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Posting content...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;//👇🏻 post content to X&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postTweet&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.twitter.com/2/tweets&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="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="s2"&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="s2"&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="s2"&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessToken&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&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="nx"&gt;message&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="nx"&gt;postTweet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content posted!&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="na"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;//👇🏻 listening for completed job&lt;/span&gt;
&lt;span class="nx"&gt;scheduleWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; has completed!`&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;Finally, you can execute the worker by running &lt;strong&gt;&lt;code&gt;npm run worker&lt;/code&gt;&lt;/strong&gt; after updating the scripts within the &lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt; file.&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;"scripts"&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;"worker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx tsx --watch src/worker.ts"&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;Congratulations! You’ve completed the project for this tutorial.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So far, you’ve learned how to authenticate users via X, store data in a Redis database, create and manage jobs with Redis and BullMQ, and integrate AI assistants into your Next.js applications using CopilotKit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://copilotkit.ai/" rel="noopener noreferrer"&gt;CopilotKit&lt;/a&gt; is an incredible tool that allows you to add AI Copilots to your products within minutes. Whether you're interested in AI chatbots and assistants or automating complex tasks, simplifies the process.&lt;/p&gt;

&lt;p&gt;If you need to build an AI product or integrate an AI tool into your software applications, you should consider CopilotKit.&lt;/p&gt;

&lt;p&gt;You can find the source code for this tutorial on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dha-stix/ai-post-generator-and-scheduler-with-copilotkit" rel="noopener noreferrer"&gt;https://github.com/dha-stix/ai-post-generator-and-scheduler-with-copilotkit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I 10x’d my Coding Productivity Using this AI Tool: I wish I had known it Earlier 🤯</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Mon, 22 Jul 2024 14:48:39 +0000</pubDate>
      <link>https://dev.to/github20k/i-10xd-my-coding-productivity-using-this-ai-tool-i-wish-i-had-known-it-earlier-2eoo</link>
      <guid>https://dev.to/github20k/i-10xd-my-coding-productivity-using-this-ai-tool-i-wish-i-had-known-it-earlier-2eoo</guid>
      <description>&lt;p&gt;I usually work on multiple projects simultaneously, and managing all these projects can become very hectic and overwhelming. So, I wanted a solution to reduce my workload.&lt;/p&gt;

&lt;p&gt;Considering the significant progress in AI in the past few years, I was specifically looking for an AI tool that can&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access my GitHub repository.&lt;/li&gt;
&lt;li&gt;Solves any given issue autonomously.&lt;/li&gt;
&lt;li&gt;Tests the code and pushes the fix to the repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frn5he0lsl9u6gjibos9m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frn5he0lsl9u6gjibos9m.gif" alt="wick" width="760" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, I started my research and stumbled upon quite a few solutions. Here is my experience working with these solutions.&lt;/p&gt;

&lt;p&gt;But before that, let’s understand what AI and SWE (Software Engineering) agents are.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are AI Agents?
&lt;/h2&gt;

&lt;p&gt;AI agents are systems powered by AI models that can autonomously perform tasks, interact with their environment, and make decisions based on their programming and the data they process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Components of AI Agents
&lt;/h3&gt;

&lt;p&gt;An AI agent has three crucial components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inference Engine&lt;/strong&gt;: Inference Engines are AI models responsible for planning and decision-making.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt;: The memory component allows the agents to manage short-term and long-term information to keep track of the workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Tools enable Agents to interact with the external environment. For instance, a GitHub tool allows the agent to extract information from repositories and make necessary changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnz8ypkrdj8pmdn81j2kg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnz8ypkrdj8pmdn81j2kg.gif" alt="minion happy" width="760" height="342"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Characteristics of an SWE Agent
&lt;/h2&gt;

&lt;p&gt;So, what makes an AI agent a SWE agent? &lt;/p&gt;

&lt;p&gt;A SWE agent is an AI agent that mimics the qualities and characteristics of a human software developer, such as&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long-term planning and reasoning&lt;/li&gt;
&lt;li&gt;Use standard developer tools.&lt;/li&gt;
&lt;li&gt;Improve code quality through testing and feedback.&lt;/li&gt;
&lt;li&gt;Debug and resolve issues autonomously.&lt;/li&gt;
&lt;li&gt;Collaborate with human counterparts as and when needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simillar to any AI agent, an SWE agent has &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A robust inference engine. Preferably state-of-the-art code models.&lt;/li&gt;
&lt;li&gt;A memory component to keep track of events.&lt;/li&gt;
&lt;li&gt;Specific tools for writing, debugging, and running codes (Isolated code environment, Internet, GitHub, File tools, etc.)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Devin - The AI Software Developer
&lt;/h2&gt;

&lt;p&gt;Devin is the first thing you will find when discussing AI agents that can code. It is an SWE agent from Cognition Labs, which started it all. It garnered a lot of attention from developers, founders, and investors and quickly became the talk of the town. &lt;/p&gt;

&lt;p&gt;However, a few things made me turn away from it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Closed Source&lt;/strong&gt;: It is a closed source. So, there is no scope for customization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI only&lt;/strong&gt;: It exclusively utilizes OpenAI models, considering Llama 3 400b launch. I wanted something more flexible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not Publicly Available&lt;/strong&gt;: It is still on the waitlist, and few people can access it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While enterprises may prefer it, I needed something more transparent and flexible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnt7j090sj3clbfg8gtl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnt7j090sj3clbfg8gtl.gif" alt="devin" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Open-source Alternatives
&lt;/h2&gt;

&lt;p&gt;The next obvious choice was all the open-source alternatives for Devin. While they are more transparent and flexible in terms of LLM providers. They still didn’t click with me.&lt;/p&gt;

&lt;p&gt;Most open-source solutions are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bloated&lt;/strong&gt;: They ship with many things I might never use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex&lt;/strong&gt;: Running these tools felt like a job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-extensible&lt;/strong&gt;: I can’t extend their capabilities using external tools and integrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That being said, they certainly hold their own merits.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop9gh0dm2kw3x3zdx4r2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop9gh0dm2kw3x3zdx4r2.png" alt="swekit" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SweKit - Simple Extensible Software Engineering Agent Framework
&lt;/h2&gt;

&lt;p&gt;After extensive searching and research, I was leaning towards building it myself until I stumbled upon this framework.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.new/swe-kit" rel="noopener noreferrer"&gt;SweKit&lt;/a&gt; is an open-source framework from &lt;a href="https://git.new/composio" rel="noopener noreferrer"&gt;Composio&lt;/a&gt; that helps you create simple and extensible SWE agents. &lt;/p&gt;

&lt;p&gt;It clicked all the criteria I was looking for.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Customizable&lt;/strong&gt;: It is simple and highly customizable. You can use the LLM providers of your choice and change the prompts to suit your requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework Agnostic&lt;/strong&gt;: It works with all the popular agentic frameworks, such as LangChain and LlamaIndex.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensible&lt;/strong&gt;: Adding more tools, such as browsing and scrapping, can easily extend the agent's capability. You can add tools from the Composio ecosystem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-source&lt;/strong&gt;: Needless to say, the code is open-source, so you can fork and add custom changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple Language Support&lt;/strong&gt;: SweKit has native support for Python and Typescript. You can go with the language of your choice. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SweKit can access any public or private repository, work on provided issues, and push changes to the repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnx2hjyyqzbvyss5jfqwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnx2hjyyqzbvyss5jfqwl.png" alt="SWE agent arch" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The SWE agent runs in Docker by default for security and isolation. This sandboxes the agent's operations, protecting against unintended consequences of arbitrary code execution. You can also run it locally, but be cautious, as it won't have Docker's protective layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbqykxszl0v79zcu7u39.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbqykxszl0v79zcu7u39.gif" alt="thank you" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;I have already started using this in my projects, and I cannot stress enough how much time and energy it has saved me. &lt;/p&gt;

&lt;p&gt;I spoke with the team building Composio, and I can confidently say this will be a game-changer.&lt;/p&gt;

&lt;p&gt;I cannot star them enough, so do me a favour, visit the repository, use the product and give them a star.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git.new/composio" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;show them support by starring the repo ⭐&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>I am suitable for the job but unsure why I can't get it! 😕</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Mon, 20 May 2024 10:41:17 +0000</pubDate>
      <link>https://dev.to/github20k/i-am-suitable-for-the-job-but-unsure-why-i-cant-get-it-5eg4</link>
      <guid>https://dev.to/github20k/i-am-suitable-for-the-job-but-unsure-why-i-cant-get-it-5eg4</guid>
      <description>&lt;p&gt;In 2020, I had just closed my previous startup and got tired of my part-time job at a project company. I was (and still am) a digital nomad and looked for remote jobs.&lt;/p&gt;

&lt;p&gt;It was pre-COVID, and remote work was not as vital as today. Too many developers (primarily freelancers) looked for jobs and a few positions.&lt;/p&gt;

&lt;p&gt;I couldn't find a job back there, and I couldn't even get an interview. With my skill set, I knew I would fit anywhere (I already had more than 7 years as a developer.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhft38itzykdcozohfgs6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhft38itzykdcozohfgs6.png" alt="Rejected" width="678" height="449"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Doing my own stuff
&lt;/h2&gt;

&lt;p&gt;I started another startup called Linvo, and it went pretty well. I got customers and made money - but it didn't work in the end.&lt;/p&gt;

&lt;p&gt;Back then, I was working in a co-working every day (9 am to 12 am) and signed unemployment to get money from the government 🙈&lt;/p&gt;

&lt;p&gt;I was in the open space of the coworking space, so I had the option to personally connect with different founders—not to get a job but to talk about literally everything.&lt;/p&gt;

&lt;p&gt;But as the conversation continued, people learned about my skills.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frhaunmgwvor6o0zy7ina.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frhaunmgwvor6o0zy7ina.gif" alt="YouKnowMe" width="760" height="355"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Hanging out in coworking spaces
&lt;/h2&gt;

&lt;p&gt;I want to be humbled, but I was offered to work at almost any startup that worked in the open space, fully remote, in almost any term I wanted. So, I started to work at &lt;a href="https://novu.co/" rel="noopener noreferrer"&gt;Novu&lt;/a&gt; for precisely 2 years.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6as772lphqfoo7a9q7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6as772lphqfoo7a9q7j.png" alt="Me" width="800" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, it's evident that it is easier to get a job when you connect with people personally (this is why startups go to events to sell their products). But I wanted to dig deeper into how I went from 0 to 100.&lt;/p&gt;

&lt;p&gt;I made a previous article about &lt;a href="https://dev.to/github20k/contributing-to-open-source-will-10x-your-chances-to-land-a-new-job-433f"&gt;contributing to open-source will 10x your chances of landing a new job&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I stand by it. But there is more.&lt;/p&gt;

&lt;p&gt;Everything is about risk in life - the more trust you have, the higher the chances somebody will hire you / use your services / buy software from you.&lt;/p&gt;

&lt;p&gt;But trust is hard.&lt;/p&gt;

&lt;p&gt;How can you get trust when you - write code?&lt;/p&gt;




&lt;h2&gt;
  
  
  What I say vs. What I am
&lt;/h2&gt;

&lt;p&gt;Whenever I looked for a freelancer (for example, a frontend developer), I couldn't determine whether:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They have an excellent personal fit&lt;/li&gt;
&lt;li&gt;They can actually write a good code&lt;/li&gt;
&lt;li&gt;They can think out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because all I could extract from them was a few words talking about themselves.&lt;/p&gt;

&lt;p&gt;As an entrepreneur, I have shifted my job from a developer to developer growth (growth hacking) as I figured this is essential for a business to grow.&lt;/p&gt;

&lt;p&gt;In my second year in Novu, I decided that I needed to build my portfolio of knowledge so people could learn anything possible about me - to gain their trust and show them my personality.&lt;/p&gt;

&lt;p&gt;So, I created my &lt;a href="https://gitroom.com" rel="noopener noreferrer"&gt;Gitroom newsletter&lt;/a&gt; and &lt;a href="https://www.youtube.com/@nevo-david" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; so people can see my marketing skills, but also my &lt;a href="https://github.com/gitroomhq/gitroom/" rel="noopener noreferrer"&gt;Gitroom open-source &lt;/a&gt; so they can see my development skills.&lt;/p&gt;

&lt;p&gt;And I was very consistent (showed up every day)—currently, the newsletter is on a 46-week streak (almost 1 year).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8thomejgye2j11dm1a8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8thomejgye2j11dm1a8q.png" alt="Streak" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And share valuable information - this is where it's essential:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I don't teach simple code stuff like algorithms&lt;/li&gt;
&lt;li&gt;I don't teach CSS and HTML&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I focus on mainly seniority-based to get their trust.&lt;br&gt;
Today, I have too many customers - I turned down a lot of jobs until I learned how to scale or get some missing skills.&lt;/p&gt;




&lt;h2&gt;
  
  
  Do this
&lt;/h2&gt;

&lt;p&gt;Since most people reading the article are purely developers (not marketers/growth hackers), I would suggest a few things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Contribute to open source&lt;/strong&gt; — the best way to show off your skills. Nothing compares to an open-source contribution to a large codebase, which is most of the proof people need.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Amplify your contribution&lt;/strong&gt; - Not everybody knows about your contribution; talk about it on every possible social media (X, Linkedin, Youtube, Daily.dev) to make people aware of what you have done.&lt;br&gt;
&lt;strong&gt;PRO TIP:&lt;/strong&gt; Tag the company to which you have contributed your code; they might re-post you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Think about your audience&lt;/strong&gt; - I see far too many "influencers" that focus on junior developers with things like (10 CSS tricks and 10 HTML tags you must know) and while this will tremendously grow your audience size because there are a lot more junior developers in the world than seniors. You will build the wrong audience. You will mark yourself with many open-source founders as a junior. It might be wrong even for a dev-rel position, as you create an audience that will never pay money.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo3h1py1um97u0w3l3xlq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo3h1py1um97u0w3l3xlq.png" alt="Do This" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Gitroom
&lt;/h2&gt;

&lt;p&gt;I am going to inject some self-promotion that can help you :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gitroomhq/gitroom" rel="noopener noreferrer"&gt;Gitroom&lt;/a&gt; is an open-source tool for social media scheduling.&lt;br&gt;
Contributing to Gitroom can achieve the two points I discussed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Contribute to a large code-base&lt;/li&gt;
&lt;li&gt;Amplify your contribution by scheduling social media posts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But there is also number three, that I think you will like.&lt;br&gt;
Gitroom is the biggest community for open-source founders; you will literally hang out with them, and they are constantly looking for remote employees worldwide.&lt;/p&gt;

&lt;p&gt;That's a great way to achieve some internal trust.&lt;/p&gt;

&lt;p&gt;After you have contributed, join our Discord channel.&lt;br&gt;
All the open-source founders are there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Please Star Gitroom if you can&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Sugar Coating
&lt;/h2&gt;

&lt;p&gt;This article is not going to sugar-coat it for you.&lt;br&gt;
If you want to get hired, you need to be good.&lt;/p&gt;

&lt;p&gt;This is not a quick scheme to "trick" people into hiring you.&lt;br&gt;
It's only a tool to amplify your knowledge and skills.&lt;/p&gt;

&lt;p&gt;Don't expect to be hired if you can't contribute to a large code base.&lt;/p&gt;

&lt;p&gt;Here is a conversation I had in my previous article:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhksdy5v7k8qpgbwo0f8x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhksdy5v7k8qpgbwo0f8x.png" alt="Codebase" width="671" height="773"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are not good enough yet, work on your skills.&lt;br&gt;
There are no magic tricks when it comes to the actual job.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🚀 The easiest way tech influencers and content writers can make money 💰</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Tue, 14 May 2024 13:41:37 +0000</pubDate>
      <link>https://dev.to/github20k/the-easiest-way-tech-influencers-and-content-writers-can-make-money-4n90</link>
      <guid>https://dev.to/github20k/the-easiest-way-tech-influencers-and-content-writers-can-make-money-4n90</guid>
      <description>&lt;p&gt;Over the last two years, I have spoken to more than 100 founders. They have all faced the same problem - they couldn't find good content writers and influencers.&lt;/p&gt;

&lt;p&gt;On the flip side, I have encountered many content writers and influencers having a hard time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Getting work&lt;/li&gt;
&lt;li&gt;Managing their orders&lt;/li&gt;
&lt;li&gt;Keep themselves safe by earning money&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's where &lt;a href="https://git.sn/gitroom-dev" rel="noopener noreferrer"&gt;Gitroom&lt;/a&gt; shines&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR: it's free. You can register and earn money.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag2oygkavq20a6kom4n0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag2oygkavq20a6kom4n0.gif" alt="Make money" width="760" height="355"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why is it different?
&lt;/h2&gt;

&lt;p&gt;Today, &lt;a href="https://gitroom.com" rel="noopener noreferrer"&gt;Gitroom&lt;/a&gt; is one of the most prominent open-source communities for open-source founders. Many of them are funded — their problem is not spending money but finding the right people to spend their money on.&lt;/p&gt;

&lt;p&gt;Next week, we will have a big launch for the new writers and influencers for the community - so you want to be there.&lt;/p&gt;

&lt;p&gt;Gitroom is really similar to &lt;a href="https://www.fiverr.com/" rel="noopener noreferrer"&gt;Fiverr&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You list yourself on the platform.
Founders contact you for promotion.&lt;/li&gt;
&lt;li&gt;You send them an offer per post.&lt;/li&gt;
&lt;li&gt;They pay for the offer, and their money will be held by Gitroom.&lt;/li&gt;
&lt;li&gt;You start to create posts from inside the system (Yes, Gitroom is a scheduling tool, also)&lt;/li&gt;
&lt;li&gt;They approve your post&lt;/li&gt;
&lt;li&gt;Once it is published, Gitroom will automatically send you the funds.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The trick about Gitroom is that the posting goes from inside of Gitroom, so you are 100% protected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pzzxq8rv7s394o6bffg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pzzxq8rv7s394o6bffg.png" alt="Safe" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How to start
&lt;/h2&gt;

&lt;p&gt;Head over to the &lt;a href="https://git.sn/gitroom-dev" rel="noopener noreferrer"&gt;Gitroom platform&lt;/a&gt; and register.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0i9cnqmw37000xmznv8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0i9cnqmw37000xmznv8.png" alt="Gitroom register" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, complete the onboarding; it's super essential that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You add your name, bio, and profile picture.&lt;/li&gt;
&lt;li&gt;Connect your Social media platform so you can offer them later.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv75zgd1nwcfoxr7tewwa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv75zgd1nwcfoxr7tewwa.png" alt="Onboarding" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go into the marketplace as a seller, connect your bank account, and add your expertise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fme9nk0qgwqtrk2yaur2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fme9nk0qgwqtrk2yaur2m.png" alt="Marketplace" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  I am done. What's now?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PLEASE MAKE SURE YOU ADD YOUR BANK DETAILS AND BUSINESS INFORMATION OR YOU WON'T SHOW UP IN THE LIST&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just wait for an email in your inbox about new offers.&lt;br&gt;
Also, &lt;a href="https://github.com/gitroomhq/gitroom/" rel="noopener noreferrer"&gt;Gitroom is fully open-sourced&lt;/a&gt;.&lt;br&gt;
So feel free to check the code and see if everything is okay.&lt;/p&gt;

&lt;p&gt;You can also suggest new features / contribute some code :)&lt;/p&gt;

&lt;p&gt;At the moment, you don't need to apply to be in the platform, but if I start to get a major amount of spam, I will change it.&lt;/p&gt;

&lt;p&gt;Let me know what you think about the system ❤️&lt;/p&gt;




&lt;p&gt;My &lt;a href="https://postiz.com" rel="noopener noreferrer"&gt;social media scheduling tool&lt;/a&gt; is now also available at Postiz.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Contributing to open-source will 10x your chances to land a new job 🚀</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Tue, 30 Apr 2024 11:06:16 +0000</pubDate>
      <link>https://dev.to/github20k/contributing-to-open-source-will-10x-your-chances-to-land-a-new-job-433f</link>
      <guid>https://dev.to/github20k/contributing-to-open-source-will-10x-your-chances-to-land-a-new-job-433f</guid>
      <description>&lt;p&gt;I have been trying to get some programmers to work for me on Upwork lately. Every person who applied raised so many questions about whether they could actually handle my project.&lt;/p&gt;

&lt;p&gt;I haven't hired any yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbps04cekis2pasb07w07.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbps04cekis2pasb07w07.gif" alt="No Skills" width="600" height="248"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding a JOB to Upwork
&lt;/h2&gt;

&lt;p&gt;I put a very simple job description with a few questions to answer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8krynn1qyxy0fpifel23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8krynn1qyxy0fpifel23.png" alt="Questions" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and started receiving many unhelpful applications. I would not be surprised if many of them were created with ChatGPT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswlrnc124ryte61zozh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswlrnc124ryte61zozh1.png" alt="unhelpful" width="675" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then got so many applications with unresolved questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How can I know they can handle my project?&lt;/li&gt;
&lt;li&gt;How do I know they don't lie?&lt;/li&gt;
&lt;li&gt;How can I know if they can handle it with a high-quality contribution?&lt;/li&gt;
&lt;li&gt;How do I know they know how to communicate with me properly?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmg3dva9mc5zxeal24kka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmg3dva9mc5zxeal24kka.png" alt="blubber" width="665" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So many unanswered questions put a big risk in hiring any of the candidates. If they are not good, I can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lose time&lt;/li&gt;
&lt;li&gt;Lose money&lt;/li&gt;
&lt;li&gt;Lost my time (because I need to teach them)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would need to interview and test every candidate (big headache)&lt;/p&gt;




&lt;h2&gt;
  
  
  Open source shines
&lt;/h2&gt;

&lt;p&gt;Now, let's assume somebody contributed to my open-source repository.&lt;/p&gt;

&lt;p&gt;Now I know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Their level&lt;/li&gt;
&lt;li&gt;Their ability to handle big projects&lt;/li&gt;
&lt;li&gt;How they communicate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I can tell you that in &lt;a href="https://novu.co/" rel="noopener noreferrer"&gt;Novu&lt;/a&gt;, many contributors have shifted their roles from contributors to employees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes most developers do
&lt;/h2&gt;

&lt;p&gt;I got an application from one person over GitHub. This is their GitHub profile:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jd2ktb7tjb3e8r85ast.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jd2ktb7tjb3e8r85ast.png" alt="Profile" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of making many contributions to different open-source repositories, they tried creating and applying their own demos.&lt;/p&gt;

&lt;p&gt;That's a big mistake.&lt;/p&gt;

&lt;p&gt;Every developer with 1+ years of experience can start something from 0; it's much easier to be in a controlled environment.&lt;/p&gt;

&lt;p&gt;Actually, contributing to a large code base (and getting merged) is a different level.&lt;/p&gt;

&lt;p&gt;Here is a message I got from the HackSquad discord:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rlz8fl98vr9bsc1zrrh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rlz8fl98vr9bsc1zrrh.png" alt="HackSquad Discord" width="739" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"But beginners can't contribute to their gigantic code bases"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is how you reduce the risk when applying for a job.&lt;/p&gt;

&lt;p&gt;SO, INSTEAD OF CREATING 100 DEMO PROJECTS, FOCUS ON 1-2 CONTRIBUTIONS FOR A BIGGER CODEBASE PROJECT.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be strategic with your contribution
&lt;/h2&gt;

&lt;p&gt;Before you contribute to any big codebase project, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it a company?&lt;/li&gt;
&lt;li&gt;Are they hiring?&lt;/li&gt;
&lt;li&gt;Do they have an open position for what I am looking for?&lt;/li&gt;
&lt;li&gt;Can I show this contribution to a similar company or in Upwork?&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Project you should contribute to
&lt;/h1&gt;

&lt;p&gt;All the listed projects are fully remote companies that hire everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;a href="https://github.com/gitroomhq/gitroom/" rel="noopener noreferrer"&gt;Gitroom&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I don't have a huge budget, but I am trying to offload some of the work. This is a good project if you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with a mid-size project&lt;/li&gt;
&lt;li&gt;Work with the biggest technologies out there, such as NextJS and NestJS&lt;/li&gt;
&lt;li&gt;Be exposed to more open-source companies (because Gitroom) that support many open-source companies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have also opened a bunch of cool issues you can start with!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gitroomhq/gitroom/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzlcqtrvpmjr03c96bydd.png" alt="Gitroom" width="800" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;a href="https://github.com/CopilotKit/CopilotKit/" rel="noopener noreferrer"&gt;CopilotKit&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Today, there is a new concept of "AI Engineer." It's mostly for people who are interested in building stuff with AI without building the AI themselves. Copilotkit is building chatbots that wrap existing LLMs. This is a good project if you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work with LLMs&lt;/li&gt;
&lt;li&gt;Work with NextJS and, in the future, more frameworks&lt;/li&gt;
&lt;li&gt;Do some cool AI shit :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/CopilotKit/CopilotKit/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9ps9yyn60w9xqx3e1ie.png" alt="CopilotKit" width="800" height="589"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;a href="https://github.com/winglang/wing/" rel="noopener noreferrer"&gt;Winglang&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;While many people go to learn computer science, they work as developers and not engineers to program full-stack software; you don't have to learn CS (I barely finished high school). If you want to pursue a career as an engineer, This is a good project if you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a transpiler that takes code and converts it to JS at the end&lt;/li&gt;
&lt;li&gt;Write sophisticated algorithms&lt;/li&gt;
&lt;li&gt;Build a deep infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkrrlly1b3x6rqc3w1ki4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkrrlly1b3x6rqc3w1ki4.png" alt="Winglang" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;a href="https://github.com/llmware-ai/llmware" rel="noopener noreferrer"&gt;LLMWare&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I asked &lt;a href="https://twitter.com/svpino" rel="noopener noreferrer"&gt;Santiago&lt;/a&gt; what the biggest trend in AI is today. He said that RAG and LLMs are the biggest hypes or mostly the future.&lt;/p&gt;

&lt;p&gt;LLMWare are killers with everything connected to RAG. This is a good project if you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Play with RAG&lt;/li&gt;
&lt;li&gt;Play and fine-tune models&lt;/li&gt;
&lt;li&gt;Be a Python professional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8az6baig5ctii4l64rgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8az6baig5ctii4l64rgx.png" alt="LLMWare" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://github.com/novuhq/novu" rel="noopener noreferrer"&gt;Novu&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I worked for Novu, so I can tell you it's a good company :)&lt;br&gt;
Their codebase is pretty big (3 years of coding). This is a good project if you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They have already hired many community members&lt;/li&gt;
&lt;li&gt;Easy codebase full-stack javascript&lt;/li&gt;
&lt;li&gt;Huge community (it's just fun)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fku2dva54034m8wq6abhp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fku2dva54034m8wq6abhp.png" alt="Novu" width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  6. &lt;a href="https://github.com/avaiga/taipy" rel="noopener noreferrer"&gt;Taipy&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I love Taipy. They build a unique Python app builder; this is a cool project because it's not as easy as full-stack JavaScript applications. This is a good project if you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn Python&lt;/li&gt;
&lt;li&gt;Showoff with a kick-ass contribution for a large codebase&lt;/li&gt;
&lt;li&gt;Be a part of a big community.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fajd52xb20zu8zy8fsgzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fajd52xb20zu8zy8fsgzt.png" alt="Taipy" width="800" height="596"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you are an open-source company also hiring, add your repository in the comment :)&lt;/p&gt;

&lt;p&gt;Also, check out &lt;a href="https://postiz.com" rel="noopener noreferrer"&gt;Postiz&lt;/a&gt; - the open-source social media scheduling tool.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I fine-tuned my model on a new programming language. You can do it too! 🚀</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Thu, 25 Apr 2024 12:31:00 +0000</pubDate>
      <link>https://dev.to/github20k/i-fine-tuned-my-model-on-a-new-programming-language-you-can-do-it-too-449</link>
      <guid>https://dev.to/github20k/i-fine-tuned-my-model-on-a-new-programming-language-you-can-do-it-too-449</guid>
      <description>&lt;p&gt;I have been using OpenAI ChatGPT-4 for a while now.&lt;br&gt;
I don't have a lot of bad stuff to say about it.&lt;br&gt;
But sometimes, it's not enough.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://github.com/winglang/wing" rel="noopener noreferrer"&gt;Winglang&lt;/a&gt;, we wanted to use OpenAI and ChatGPT-4 to answer people's questions based on our documentation.&lt;/p&gt;

&lt;p&gt;Your options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;a href="https://platform.openai.com/docs/assistants/overview?context=with-streaming" rel="noopener noreferrer"&gt;OpenAI assistant&lt;/a&gt; or any other vector-based database with (RAG). It worked nicely since Wing looked like JS, but there were still many mistakes.&lt;/li&gt;
&lt;li&gt;Passing the entire documentation into the context window is super expensive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Soon enough, we realized that was not going to work.&lt;br&gt;
It's time to host our own LLM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9x9ng6feh6x739djcb0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9x9ng6feh6x739djcb0.gif" alt="Problem" width="720" height="504"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  Your LLM dataset
&lt;/h1&gt;

&lt;p&gt;Before we train our model, we need to create data that will be used to train the model. In our case, the Winglang documentation. I will do something pretty simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extract all the URLs from the sitemap, set a GET request, and collect the content.&lt;/li&gt;
&lt;li&gt;Parse it; we want to convert all the HTML into readable content.&lt;/li&gt;
&lt;li&gt;Run it with ChatGPT 4 to convert the content into a CSV as the dataset.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It should be something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2xq8lm4b31k8pop4gmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2xq8lm4b31k8pop4gmc.png" alt="LLM DATASET" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you finish, save the CSV with one column named &lt;code&gt;text&lt;/code&gt; and add the question and the answer. We will use it later. It should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text
&amp;lt;s&amp;gt;[INST]How to define a variable in Winglang[/INST] let a = 'Hello';&amp;lt;/s&amp;gt;
&amp;lt;s&amp;gt;[INST]How to create a new lambda[/INST] bring cloud; let func = new cloud.Function(inflight () =&amp;gt; { log('Hello from the cloud!'); });&amp;lt;/s&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save it on your computer in a new folder called &lt;code&gt;data&lt;/code&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Autotrain, your model
&lt;/h1&gt;

&lt;p&gt;My computer is pretty weak, so I have decided to go into a smaller model - 7b parameters: &lt;code&gt;mistralai/Mistral-7B-v0.1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There are millions of ways to train a model. We will use Huggingface Autotrain. We will use their CLI without running any Python code 🚀&lt;/p&gt;

&lt;p&gt;When you use Autotrain from Huggingface, you can train it on your computer (my approach here) or train it on their servers (pay money) and train larger models.&lt;/p&gt;

&lt;p&gt;I have no GPU with my old Macbook Pro M1 2021. thank you, Apple 🍎.&lt;/p&gt;

&lt;p&gt;Let's install autotrain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; autotrain-advanced
autotrain setup &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; setup_logs.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, all we need to do is run the autotrain command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;autotrain llm &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--train&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--model&lt;/span&gt; &lt;span class="s2"&gt;"mistralai/Mistral-7B-Instruct-v0.2"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--project-name&lt;/span&gt; &lt;span class="s2"&gt;"autotrain-wing"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data-path&lt;/span&gt; data/ &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--text-column&lt;/span&gt; text &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--lr&lt;/span&gt; &lt;span class="s2"&gt;"0.0002"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--batch-size&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--epochs&lt;/span&gt; &lt;span class="s2"&gt;"3"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--block-size&lt;/span&gt; &lt;span class="s2"&gt;"1024"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--warmup-ratio&lt;/span&gt; &lt;span class="s2"&gt;"0.1"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--lora-r&lt;/span&gt; &lt;span class="s2"&gt;"16"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--lora-alpha&lt;/span&gt; &lt;span class="s2"&gt;"32"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--lora-dropout&lt;/span&gt; &lt;span class="s2"&gt;"0.05"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--weight-decay&lt;/span&gt; &lt;span class="s2"&gt;"0.01"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--gradient-accumulation&lt;/span&gt; &lt;span class="s2"&gt;"4"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--quantization&lt;/span&gt; &lt;span class="s2"&gt;"int4"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--mixed-precision&lt;/span&gt; &lt;span class="s2"&gt;"fp16"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--peft&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once finished you will have a new directory called "autotrain-wing" with the new fine-tuned model 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  Playing with the model
&lt;/h2&gt;

&lt;p&gt;To play with the model, start by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;transformers torch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once completed, create a new Python file named invoke.py with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;

&lt;span class="c1"&gt;# Path to your local model directory
&lt;/span&gt;&lt;span class="n"&gt;model_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./autotrain-wing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Load the model and tokenizer from the local directory
&lt;/span&gt;&lt;span class="n"&gt;classifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text-classification&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Example text to classify
&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Example text to classify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then you can run it by running the CLI command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python invoke.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you are done 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  Keep on working on your LLMs
&lt;/h2&gt;

&lt;p&gt;I am still learning about LLMs.&lt;br&gt;
One thing I realized is that it's not so easy to track changes with your models.&lt;/p&gt;

&lt;p&gt;You can't really use it with Git because a model can reach a very large size &amp;gt; 100 GB; it doesn't make much sense - git doesn't handle it nicely.&lt;/p&gt;

&lt;p&gt;A better way to do this is with a tool called &lt;a href="https://github.com/jozu-ai/kitops/" rel="noopener noreferrer"&gt;KitOps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think it will soon be a standard in the world of LLM, so make sure you star this library so you can use it later.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download the latest &lt;a href="https://github.com/jozu-ai/kitops/releases/tag/v0.1.3" rel="noopener noreferrer"&gt;KitOps release&lt;/a&gt; and &lt;a href="https://kitops.ml/docs/cli/installation.html" rel="noopener noreferrer"&gt;install it&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to the model folder and run the command to pack your LLM:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kit pack &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;You can also push it to Docker hub by running
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kit pack &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;your registry address]/[your repository name]/mymodelkit:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;💡 To learn how to use DockerHub &lt;a href="https://kitops.ml/docs/quick-start.html" rel="noopener noreferrer"&gt;check this&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jozu-ai/kitops" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;⭐️ Star KitOps so you can find it again later ⭐️&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jozu-ai/kitops" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F362tc5831i5ozbsau2o3.png" alt="StarRepo" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I started a new YouTube channel mostly about open-source marketing :)&lt;/p&gt;

&lt;p&gt;(Like how to get Stars, Forks and Client)&lt;/p&gt;

&lt;p&gt;If that's something that interests you, feel free to subscribe to it here:&lt;br&gt;
&lt;a href="https://www.youtube.com/@nevo-david?sub_confirmation=1" rel="noopener noreferrer"&gt;https://www.youtube.com/@nevo-david?sub_confirmation=1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>React Crazy: This AI library transformed my app to the next level</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Thu, 11 Apr 2024 13:08:04 +0000</pubDate>
      <link>https://dev.to/github20k/react-crazy-this-ai-library-transformed-my-app-to-the-next-level-b4i</link>
      <guid>https://dev.to/github20k/react-crazy-this-ai-library-transformed-my-app-to-the-next-level-b4i</guid>
      <description>&lt;p&gt;I have been building tons of applications.&lt;br&gt;
My latest one is &lt;a href="https://platform.gitroom.com/" rel="noopener noreferrer"&gt;Gitroom&lt;/a&gt;. It helps you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Schedule your posts on multiple social media platforms and cross-post them to publishing platforms such as DEV, Medium, and Hashnode.&lt;/li&gt;
&lt;li&gt;Track your GitHub repository metrics&lt;/li&gt;
&lt;li&gt;Monitor GitHub trendings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(&lt;a href="https://github.com/gitroomhq/gitroom/" rel="noopener noreferrer"&gt;it's open-sourced&lt;/a&gt; 🙏🏻)&lt;br&gt;
That's nice and all, but here is the real kicker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrz11l4ks7fqs6snm43l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrz11l4ks7fqs6snm43l.gif" alt="Kicker" width="720" height="432"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Add AI to your application
&lt;/h2&gt;

&lt;p&gt;I see tons of AI libraries every day, and most of them are really cool, but I ask myself, will they help me in real life?&lt;/p&gt;

&lt;p&gt;Yes, &lt;a href="https://github.com/yoheinakajima/babyagi" rel="noopener noreferrer"&gt;babyagi&lt;/a&gt; might be the next big thing. But honestly, I don't see anything I can do with it.&lt;/p&gt;

&lt;p&gt;So what can you do with AI, and what do people usually do?&lt;/p&gt;

&lt;p&gt;I think in today's ChatGPT world and local LLMs, the use case is pretty simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Auto-complete content&lt;/strong&gt; - perfect for Gitroom to let you generate additional information or use something like GitHub copilot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automation&lt;/strong&gt; - You pass content to the LLM, which returns a JSON with operations you can perform.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Function calling&lt;/strong&gt; - Mostly with ChatGPT, you pass different functions to the LLM, and they decide which one to run.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Miscellaneous&lt;/strong&gt; - Classification, translation, etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think "function calling" is not leveraged enough because adding it in a way that makes sense is complex.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1525cwviu2adl67iei9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1525cwviu2adl67iei9.gif" alt="Add AI" width="600" height="310"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Help your users with everything
&lt;/h2&gt;

&lt;p&gt;I admit I love to build stuff, but I sometimes skip developing a good UX, which causes people to leave the system because they don't know what to do.&lt;/p&gt;

&lt;p&gt;I think inherently, if you build systems for developers, you can get away with it - because they are more sophisticated.&lt;/p&gt;

&lt;p&gt;But that is mostly not the case.&lt;br&gt;
You should have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Onboardings&lt;/li&gt;
&lt;li&gt;Tutorials&lt;/li&gt;
&lt;li&gt;YouTube videos (inside your system, yes yes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where AI can save you without writing too much code.&lt;/p&gt;


&lt;h2&gt;
  
  
  Add a chatbot that can do everything for you
&lt;/h2&gt;

&lt;p&gt;So, one of the things more and more companies offer is a chatbot that can interact with your data and perform actions for the user.&lt;/p&gt;

&lt;p&gt;For example, I can tell the chatbot I want to schedule a new post for Gitroom at 7:00 p.m. US time.&lt;/p&gt;

&lt;p&gt;And it will do it for me.&lt;/p&gt;

&lt;p&gt;The problem with most of the solutions I found is that they are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Not open-source&lt;/li&gt;
&lt;li&gt;It is not an infrastructure product but a complete product that is mainly for product managers.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  CopilotKit can help you
&lt;/h2&gt;

&lt;p&gt;So, I found this incredible &lt;a href="https://github.com/CopilotKit/CopilotKit" rel="noopener noreferrer"&gt;open-source library&lt;/a&gt; licensed under MIT - which is fantastic.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/DJRG9oPiW-I"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It's just a chatbot sitting on your right sidebar.&lt;/p&gt;

&lt;p&gt;You feed it with:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your current context information.&lt;/li&gt;
&lt;li&gt;Your data resources, such as your database, dropbox, Google Drive, etc.&lt;/li&gt;
&lt;li&gt;Different functions in the system can be called.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you have finished doing that, it's just like magic.&lt;br&gt;
Does somebody want to schedule a post?&lt;/p&gt;

&lt;p&gt;It will trigger the &lt;code&gt;schedulePost&lt;/code&gt; function.&lt;br&gt;
Of course, it uses the ChatGPT "function calling" in the background, but it simplifies everything.&lt;/p&gt;

&lt;p&gt;I think it fits any app. You can use it with big LLMs like ChatGPT / Gemini, but also with smaller ones like LLAMA2 and Mistral.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/CopilotKit/CopilotKit" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Check out CopilotKit&lt;/a&gt;
&lt;/p&gt;




&lt;p&gt;I started a new YouTube channel mostly about Tech, open-source, and marketing :)&lt;/p&gt;

&lt;p&gt;If that's something that interests you, feel free to subscribe to it here:&lt;br&gt;
&lt;a href="https://www.youtube.com/@nevo-david?sub_confirmation=1" rel="noopener noreferrer"&gt;https://www.youtube.com/@nevo-david?sub_confirmation=1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>I sold my startup because of bugs: I wish I had this serverless repository!</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Thu, 04 Apr 2024 11:00:03 +0000</pubDate>
      <link>https://dev.to/github20k/i-sold-my-startup-because-of-bugs-i-wish-i-had-this-serverless-repository-4l3a</link>
      <guid>https://dev.to/github20k/i-sold-my-startup-because-of-bugs-i-wish-i-had-this-serverless-repository-4l3a</guid>
      <description>&lt;p&gt;In 2021, I built a startup called Linvo, a LinkedIn automation tool. It generated good money but also had a high burn rate.&lt;/p&gt;

&lt;p&gt;I can tell you that I lost most of my money as a young entrepreneur (entirely bootstrapped) 😆&lt;/p&gt;

&lt;p&gt;The problem with my system is that it kept on failing; I am not the best programmer in the world, but let me elaborate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4l95m758p7m9fg4914dc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4l95m758p7m9fg4914dc.png" alt="Revenue" width="723" height="278"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Puppeteer sucks your memory
&lt;/h2&gt;

&lt;p&gt;Linvo went into a few iterations during its lifetime. I used the tech that I know: React and NestJS.&lt;/p&gt;

&lt;p&gt;Basically, any automated cloud scraping goes into making tasks and then solving them.&lt;/p&gt;

&lt;p&gt;It looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9n4d78oe0cz6vxl1y34n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9n4d78oe0cz6vxl1y34n.png" alt="Workers and scraping" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cron runs every 10 minutes, looks for new stuff to do, and sends it to the queue.&lt;/li&gt;
&lt;li&gt;Workers take tasks from the queue and process them.&lt;/li&gt;
&lt;li&gt;Save everything to the DB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a very naive solution that was running on multiple EC2 (AWS) and Redis.&lt;/p&gt;

&lt;p&gt;In theory, it should work - Yes, you would need to scale the workers horizontally, but that was not my problem.&lt;/p&gt;

&lt;p&gt;I started to experience something else - &lt;strong&gt;memory leaks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As you probably know, &lt;a href="https://pptr.dev/" rel="noopener noreferrer"&gt;Puppeteer&lt;/a&gt; - a chromium automated browser, is heavy (same as Chrome on your computer), and I was running lots of them - they sucked both my memory - causing the servers to stop working and took the internet bandwidth.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5fsl47a1yzumo3qexa8h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5fsl47a1yzumo3qexa8h.gif" alt="Sucks" width="760" height="425"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Needed a solution
&lt;/h2&gt;

&lt;p&gt;Refactoring sounds like - yeah, let's do that, but my Intercom support was filled with support tickets (I already had many users), and I knew I had to create some crazy refactoring.&lt;/p&gt;

&lt;p&gt;I had an idea for a solution - let's use AWS lambda.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lambda start&lt;/li&gt;
&lt;li&gt;Do the task&lt;/li&gt;
&lt;li&gt;Die (most of the time)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It doesn't suck your internet.&lt;br&gt;
It will die and not cause a memory leak.&lt;/p&gt;

&lt;p&gt;It's a bit more expensive because Lambdas were not meant to run indefinitely—that would remove the whole concept, but I was desperate. (Well, the good thing is that you don't need to think about scale.)&lt;/p&gt;

&lt;p&gt;Here is the new infrastructure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsr304vf0z81f0bqfxnup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsr304vf0z81f0bqfxnup.png" alt="New Infra" width="800" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Event bridge cron running every 1 minute (that's the minimum)&lt;/li&gt;
&lt;li&gt;Lambda that creates six events for the queue (making it like the cron runs every 10 seconds)&lt;/li&gt;
&lt;li&gt;SQS queue (bye bye, Redis)&lt;/li&gt;
&lt;li&gt;Lambdas shooting out with auto-scaling (yay?)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Vendor Locking
&lt;/h2&gt;

&lt;p&gt;As you probably understand from the context - now I am all in with AWS, but I didn't mind - only how I would test it on my computer.&lt;/p&gt;

&lt;p&gt;Back in the day, I used &lt;a href="https://github.com/aws/aws-sam-cli" rel="noopener noreferrer"&gt;Sam&lt;/a&gt;. It's almost the same as &lt;a href="https://www.serverless.com/" rel="noopener noreferrer"&gt;Serverless&lt;/a&gt; to create the entire environment quickly.&lt;/p&gt;

&lt;p&gt;And yes, they do bring some local testing. They can take your lambdas and turn them into endpoints! Yay!&lt;/p&gt;

&lt;p&gt;But I was using Event Bridge, SQS, and Lambdas. That was just not possible.&lt;/p&gt;

&lt;p&gt;I have encountered &lt;a href="https://github.com/localstack/localstack" rel="noopener noreferrer"&gt;localstack&lt;/a&gt;. It was supposed to help me build an entire AWS stack on my computer, but many things were not supported back then, such as Lambda layers. And I was overwhelmed in using it.&lt;/p&gt;

&lt;p&gt;So I started to create my "own" infrastructure where I deployed one "test" SQS on AWS and ran local code with it (a function that calls a function), and it was - bad.&lt;/p&gt;

&lt;p&gt;I did not work well in production; I felt like the word was squeezing up on me back in the day.&lt;/p&gt;

&lt;p&gt;I just wanted to get rid of this startup; I even offered it to people for free, taking the customers and rid myself of that problem.&lt;/p&gt;

&lt;p&gt;Long story short, I managed to sell the system for a low price, but lately, I discovered something interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Winglang - Typescript like dialect for the cloud
&lt;/h2&gt;

&lt;p&gt;I guess my pain was real, and even though I would be happier to find this back in the day - I am glad it's alive today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/winglang/wing" rel="noopener noreferrer"&gt;Winglang&lt;/a&gt; helps you to build the same cloud infrastructure as I used, but the nice thing is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It doesn't require you to use any configuration files. You basically define the entire infrastructure with code (you can check their entire preflight and inflight documentation)&lt;/li&gt;
&lt;li&gt;You can run it locally - thank you, god, 🙏🏻🙏🏻🙏🏻🙏🏻 with all the infrastructure included.&lt;/li&gt;
&lt;li&gt;You can deploy it to any cloud provider, and you don't have to use AWS. They can literally generate any Terraform or cloud formation for easy deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I talked to the founder of Winglang, Elad (builder of the famous CDK), and he said something that made me twitch.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can literally work on your projects when you are on an airplane and write tests for it 🤯&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I can't give them enough stars myself - but do me a favor and star their repository and of course, use it for your next project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/winglang/wing" rel="noopener noreferrer"&gt;https://github.com/winglang/wing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgiofk3zupgxjgnc57zw5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgiofk3zupgxjgnc57zw5.gif" alt="Thank you" width="600" height="335"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;I am angry at Winglang. I wish they had done it sooner. Now they show up. When it's all about AI?&lt;/p&gt;

&lt;p&gt;I started a new YouTube channel mostly about Tech, open-source, and marketing :)&lt;/p&gt;

&lt;p&gt;If that's something that interests you, feel free to subscribe to it here:&lt;br&gt;
&lt;a href="https://www.youtube.com/@nevo-david?sub_confirmation=1" rel="noopener noreferrer"&gt;https://www.youtube.com/@nevo-david?sub_confirmation=1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>My new open-source repository to schedule all your content!</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Tue, 26 Mar 2024 08:23:14 +0000</pubDate>
      <link>https://dev.to/github20k/my-new-open-source-repository-to-schedule-all-your-content-2f2a</link>
      <guid>https://dev.to/github20k/my-new-open-source-repository-to-schedule-all-your-content-2f2a</guid>
      <description>&lt;p&gt;Hi there, community!&lt;br&gt;
A few years ago, I shared my story of closing my previous startup and &lt;a href="https://dev.to/nevodavid/i-turned-my-startup-into-open-source-4efh"&gt;making it open-source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since then, I have worked for Novu, an open-source notification infrastructure, and I have actually learned a lot about the power of an open-source community.&lt;/p&gt;

&lt;p&gt;I have written 74 posts on DEV that generated &lt;strong&gt;1,182,911 views&lt;/strong&gt; 🤗&lt;br&gt;
Any by that making Novu one of the most popular open-source repositories &lt;strong&gt;(31k stars)&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  I started to talk about it
&lt;/h2&gt;

&lt;p&gt;I created a newsletter called &lt;a href="https://gitroom.com/" rel="noopener noreferrer"&gt;Gitroom&lt;/a&gt; (formerly GitHub20k) and wrote about everything I have done during the year, from posting actual-value tutorials on DEV to promoting the repository using influencers.&lt;/p&gt;

&lt;p&gt;I have talked to more than 30 open-source maintainers per month! Helping them get visibility in their repository.&lt;/p&gt;

&lt;p&gt;But there is one nothing I have never solved.&lt;br&gt;
My tactics are very stressful. It was not randomly writing articles.&lt;br&gt;
But I was writing them at the right time and promoting them on different Reddit and social media channels.&lt;/p&gt;

&lt;p&gt;The problem is that your launch is stuck before the article is published—you can't time anything, so you have to do it during the week.&lt;/p&gt;

&lt;p&gt;It becomes tough if other people are involved in the launch; I used to miss much of it. So, I decided to create the Gitroom Platform.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Gitroom Platform
&lt;/h2&gt;

&lt;p&gt;The Gitroom platform is the best tool for scheduling your open-source launches. It's 100% open-source! Check and star it here.&lt;br&gt;
&lt;a href="https://github.com/gitroomhq/gitroom" rel="noopener noreferrer"&gt;https://github.com/gitroomhq/gitroom&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;NextJS (tailwind)&lt;/li&gt;
&lt;li&gt;NestJS&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Analytics
&lt;/h3&gt;

&lt;p&gt;Starting with the basics, I wanted to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; When is the most performant day (regarding the number of stars), and then cross-reference it to the launch week I have done.
&lt;/li&gt;
&lt;li&gt;Know when I am trending over GitHub (get a notification)
&lt;/li&gt;
&lt;li&gt;Know when the GitHub feed will be refreshed to schedule my content accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdff1atrdoflj1ppifvvp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdff1atrdoflj1ppifvvp.png" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Launches Page
&lt;/h3&gt;

&lt;p&gt;To launch, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To have all the channels used in open-source from Social Media such as Reddit to publishing articles such as &lt;a href="http://DEV.to?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=the-gitroom-platform-is-live" rel="noopener noreferrer"&gt;DEV.to&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;See the timeline for the next refresh so I can plan it accordingly.
&lt;/li&gt;
&lt;li&gt;Add comments and collaborate with my team before the launch happens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsu68b0swdta8t8x7n7n4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsu68b0swdta8t8x7n7n4.gif" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Schedule Page
&lt;/h3&gt;

&lt;p&gt;This is where the magic happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can &lt;strong&gt;cross-post&lt;/strong&gt; to multiple channels at the same time (say DEV, Hashnode, and Medium)
&lt;/li&gt;
&lt;li&gt;You can post to more complex channels, such as Reddit, where you must define &lt;strong&gt;flair&lt;/strong&gt; and subreddit.
&lt;/li&gt;
&lt;li&gt;You can edit everything globally and then switch to a specific channel.
&lt;/li&gt;
&lt;li&gt;See the preview of how it will look in the existing channel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use links from previous scheduled posts&lt;/strong&gt; before they are posted! You can also use it as a canonical link!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.beehiiv.com%2Fcdn-cgi%2Fimage%2Ffit%3Dscale-down%2Cformat%3Dauto%2Conerror%3Dredirect%2Cquality%3D80%2Fuploads%2Fasset%2Ffile%2Fd8ac54a6-d9a7-4219-a17f-40b9c3692928%2FCleanShot_2024-03-16_at_15.30.43.gif%3Ft%3D1710578073" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.beehiiv.com%2Fcdn-cgi%2Fimage%2Ffit%3Dscale-down%2Cformat%3Dauto%2Conerror%3Dredirect%2Cquality%3D80%2Fuploads%2Fasset%2Ffile%2Fd8ac54a6-d9a7-4219-a17f-40b9c3692928%2FCleanShot_2024-03-16_at_15.30.43.gif%3Ft%3D1710578073" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The community's future!
&lt;/h2&gt;

&lt;p&gt;This is the first version of Gitroom, mainly for planning your launch. &lt;strong&gt;Here is what you should expect:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exchange or buy posts from other community members and influencers! &lt;strong&gt;YES&lt;/strong&gt;! Influencers will create posts for you, and they will appear on the timeline. What is the best thing? They will be paid only once the post is published (Good incentives)
&lt;/li&gt;
&lt;li&gt;Be part of the OSS friends, an API that lists all the open-source companies in the system - &lt;strong&gt;Great for SEO.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add testimonials and &lt;strong&gt;“used by”&lt;/strong&gt; with other open-source friends!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And Also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Import from other platforms such as Notion&lt;/strong&gt;—I personally write all my blog posts on Notion, but every time I copy them, I need to upload all the pictures manually.&lt;/li&gt;
&lt;li&gt;More channels to schedule are available, such as Discord and Mastodon.
&lt;/li&gt;
&lt;li&gt;Automatic cross-posting (if you don’t want to use Gitroom scheduler)
&lt;/li&gt;
&lt;li&gt;Media generators, like the number of stars you have.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Help me out! 🤗&lt;br&gt;
This is a new project, 100% open-source (first of his kind!)&lt;br&gt;
Any star you can give me will help me grow it even more ❤️&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gitroomhq/gitroom" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Star it here ❤️&lt;/a&gt;
&lt;/p&gt;




&lt;p&gt;You can now find my &lt;a href="https://postiz.com" rel="noopener noreferrer"&gt;schedule tool&lt;/a&gt; on Postiz.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>react</category>
    </item>
    <item>
      <title>Mirrord trick to get on hackernews</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Wed, 10 Jan 2024 15:22:54 +0000</pubDate>
      <link>https://dev.to/github20k/mirrord-trick-to-get-on-hackernews-3cpb</link>
      <guid>https://dev.to/github20k/mirrord-trick-to-get-on-hackernews-3cpb</guid>
      <description>&lt;p&gt;I had the pleasure of talking to &lt;a href="https://www.linkedin.com/in/eyal-bukchin" rel="noopener noreferrer"&gt;Eyal&lt;/a&gt; @ CTO at Metalbear and the maintainer of &lt;a href="https://github.com/metalbear-co/mirrord" rel="noopener noreferrer"&gt;Mirrord&lt;/a&gt;. I got some crazy insights.&lt;/p&gt;

&lt;p&gt;You can watch the full video here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9i3ittrvltk6ztaod7m.png" alt="Youtube" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting on Hackernews five times
&lt;/h2&gt;

&lt;p&gt;The team at Mirrord had a secret to get into Hackernews.&lt;br&gt;&lt;br&gt;
They knew that if they published their post on Hackernews, the chances they would get in were rare (They have tried multiple times and failed.)&lt;/p&gt;

&lt;p&gt;So they would go to Reddit and promote their content there, wait for a bit, and let somebody else with a higher Karma post their article on Hackernews.&lt;/p&gt;

&lt;p&gt;But you have to understand that their content was super technical. It was not about building another “todo” app or how to use Kubernetes.&lt;br&gt;&lt;br&gt;
&lt;a href="https://news.ycombinator.com/item?id=35081033" rel="noopener noreferrer"&gt;Here is an example of their post.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that the person who posted them is the Founder/CEO of Pipedream with &lt;strong&gt;130,687 karma.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They have managed to nail it like that multiple times.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Want a free trick?&lt;/strong&gt; Copy their article to your tool and release it on various subreddits.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Kubernetes trick that blew my mind
&lt;/h2&gt;

&lt;p&gt;Honestly, I didn’t even know it was possible. They went into the Kubernetes blog and contributed a blog post (Their blog is open-source). They have made a comparison between their tool and other tools. This article still keeps sending them traffic daily - mind-blowing 🤯&lt;/p&gt;

&lt;p&gt;Try it out, visit their &lt;a href="https://github.com/kubernetes/website/tree/main/content/en/blog/_posts" rel="noopener noreferrer"&gt;website repository blog&lt;/a&gt;, and contribute your blog. Maybe you can even contribute to an existing one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Running Google Ads
&lt;/h2&gt;

&lt;p&gt;Honestly, every founder I talk to is usually unhappy with ads, but we all do it (at least try.) Mirrord ran ads mostly on their competitor’s names as it’s usually the cheapest and most targeted. I find ads very problematic because most developers have an ad blocker, so measuring the conversion is hard.&lt;/p&gt;

&lt;p&gt;I recently ran my ads on Reddit and couldn’t use the pixel properly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q59na1287lkxgtrt98m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q59na1287lkxgtrt98m.png" width="800" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You want a platform that has a “&lt;strong&gt;conversion&lt;/strong&gt;” API. Unfortunately, Reddit doesn’t have it yet - &lt;a href="https://business.twitter.com/en/help/campaign-measurement-and-analytics/conversion-tracking-for-websites.html" rel="noopener noreferrer"&gt;Twitter does&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And even with that, it’s hard to get it.&lt;/p&gt;

&lt;p&gt;Developers tend not to click on ads and then search for the brand on Google &lt;strong&gt;(we have all done it)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I don’t recommend people run ads in general, only when you are in a scaling mode (you have maximized all the other channels)&lt;/p&gt;




&lt;h2&gt;
  
  
  I invite you to register for my newsletter.
&lt;/h2&gt;

&lt;p&gt;This newsletter is good for you if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are considering open-sourcing your product (or building a new one).&lt;/li&gt;
&lt;li&gt;You are considering opening a by-product and open-source it (to reflect on your main product).&lt;/li&gt;
&lt;li&gt;You are in tech and want growth without the stars / without GitHub trending.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a 100% free newsletter (and always will be). Feel free to register at:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitroom.com/" rel="noopener noreferrer"&gt;https://gitroom.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86ywkzncq6erg44d6xy9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86ywkzncq6erg44d6xy9.gif" alt="In for tech" width="720" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Discord Plan for open-source in 2024</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Wed, 03 Jan 2024 13:18:22 +0000</pubDate>
      <link>https://dev.to/github20k/the-discord-plan-for-open-source-in-2024-2596</link>
      <guid>https://dev.to/github20k/the-discord-plan-for-open-source-in-2024-2596</guid>
      <description>&lt;p&gt;Hi everyone!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I wish you all a fantastic New Year&lt;/strong&gt; 🥳&lt;/p&gt;

&lt;p&gt;Mine is going to be stressful and fun. I hope yours is too!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc0x5stpgnszcgfa1ift.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc0x5stpgnszcgfa1ift.gif" width="760" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://discord.com?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=the-discord-plan-for-open-source-in-2024" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; is a chat messaging platform you can run to interact with developers for your products. It can be used for marketing, support, or to build a strong community for your product.&lt;/p&gt;

&lt;p&gt;During my time at Novu, we always tried to make the Discord server &lt;strong&gt;“active.”&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This is something that I have experienced with many founders.&lt;br&gt;&lt;br&gt;
They want their Discord to be more than just a &lt;strong&gt;“support”&lt;/strong&gt; channel.&lt;/p&gt;

&lt;p&gt;Most founders aim to make the Discord channel active just from people engaging with each other, &lt;strong&gt;but how do you do it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is a list of things you can try that worked well for me in Gitroom and HackSquad Discord servers.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Make people come back for more
&lt;/h2&gt;

&lt;p&gt;I want to start with the simplest example - &lt;a href="https://www.midjourney.com/?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=the-discord-plan-for-open-source-in-2024" rel="noopener noreferrer"&gt;&lt;strong&gt;Midjourney&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Their main product lives on Discord; if you want to generate images, you must do it with the Discord bot. Whenever people come to create pictures, they are exposed to other people and interact with them. That was a genius move.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://discord.gitroom.com?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=the-discord-plan-for-open-source-in-2024" rel="noopener noreferrer"&gt;Gitroom&lt;/a&gt;, I implemented a mechanism for people to launch their content. Since most people launch their content every week - they have to come back &lt;strong&gt;every week&lt;/strong&gt; and, at the same time, interact with other people.&lt;/p&gt;

&lt;p&gt;That’s why you usually see tons of activity in Gitroom every Monday.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fls79ab8g425e8l2p12e9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fls79ab8g425e8l2p12e9.png" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Make a “non-product” Discord
&lt;/h2&gt;

&lt;p&gt;When your Discord server is something like “Novu,” visitors of your Discord have the concept of “This is the Novu product. Let’s talk about that,” while this is what most products do, you don’t have to.&lt;/p&gt;

&lt;p&gt;Our Discord server could be as well as “Notification Infrastructure.” Now, we have broadened our audience and given them a place to learn everything about notifications.&lt;/p&gt;

&lt;p&gt;HackSquad was super active because it was a developer-based server where people could talk about anything.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9k2f69pf3ryqgne9a9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9k2f69pf3ryqgne9a9n.png" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Join with intent
&lt;/h2&gt;

&lt;p&gt;Lately, I have experienced that people that I give a pitch over our Discord server during my calls are a lot more active than people who join on their own.&lt;/p&gt;

&lt;p&gt;I think that’s the main secret in building an active community - and while you can’t talk to everybody, only a few are already pretty good because they will be active and involve other people.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other options you can do are:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Give more information during the Discord &lt;strong&gt;“onboarding”&lt;/strong&gt; wizard so people can understand what they can get by being active.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Show some content or a YouTube video next to the discord link so people can learn about the value of the server.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tag people who join in different activities and ask for their opinions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F23ljbzhnlwqej6kg2tte.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F23ljbzhnlwqej6kg2tte.png" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you like this blog post so far?&lt;/p&gt;

&lt;p&gt;Make sure you register to the newsletter to read the next one&lt;/p&gt;

&lt;p&gt;Subscribe&lt;/p&gt;

&lt;p&gt;* Add your email, a video of getting the first 1,000 stars will be sent to your email&lt;/p&gt;

&lt;p&gt;Or invite your friend to learn &lt;a href="https://howtogetgithubstars.com" rel="noopener noreferrer"&gt;How to get GitHub stars&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Retain
&lt;/h2&gt;

&lt;p&gt;Bringing people to your Discord is a part of the “&lt;strong&gt;Acquisition&lt;/strong&gt;” process, but making them stay is part of the “&lt;strong&gt;Retention&lt;/strong&gt;” process.&lt;/p&gt;

&lt;p&gt;In HackSquad, bringing people back to Discord makes them more active.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Instead of making a YouTube Live of a webinar or a Zoom Live, I would make a Discord Live and then send people back to Discord through the newsletter.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I run repeatable events that go beyond “How to use Novu.” I would actually do more generic stuff to attract more people.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I run Discord giveaways, making developers come back.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I constantly write on Social Media about the benefits of being a part of Discord.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nqg455rnu0bgqhvbjjv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nqg455rnu0bgqhvbjjv.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Appoint moderators
&lt;/h2&gt;

&lt;p&gt;The first thing I have done with Gitroom is find the first active and talented people on Discord and make them mods. That’s one of my best moves to make the community 10x more alive.&lt;/p&gt;

&lt;p&gt;Once the community grows a bit, I intend to bring more mods.&lt;/p&gt;

&lt;p&gt;In HackSquad, I appointed ten moderators in 1 month - &lt;strong&gt;Best Decision Ever.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I am so happy to have such talented people as &lt;a href="https://www.linkedin.com/in/nathan-tarbert/?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=the-discord-plan-for-open-source-in-2024" rel="noopener noreferrer"&gt;Nathan&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/srbhr/?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=the-discord-plan-for-open-source-in-2024" rel="noopener noreferrer"&gt;Saurabh&lt;/a&gt;, who help me grow the community and put it all together.&lt;/p&gt;

&lt;p&gt;Mods automatically become more active when you give them &lt;strong&gt;“power”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8brktta86gwcwff2gkm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8brktta86gwcwff2gkm.png" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Create an onboarding funnel
&lt;/h2&gt;

&lt;p&gt;When somebody joins your Discord, that will be the time that they will be the most active and motivated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You should use this time!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ask them some questions on Discord and include them in some conversations to give some opinions.&lt;/p&gt;

&lt;p&gt;Also, &lt;strong&gt;DM them&lt;/strong&gt;. While this is not connected to being active on Discord - it’s an excellent time to understand your community members and extract some information from them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Why did you join?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What are you building?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Who told you about us?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why do you want to get from this community?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try even to go for a 10-minute call if you can.&lt;/p&gt;

&lt;p&gt;Here is the thing: you are not active &lt;strong&gt;24/7&lt;/strong&gt;, but if you have mods from around the world - they can help you!&lt;/p&gt;

&lt;p&gt;Just make sure not all the mods DM the same person at the same time - that’s not nice 🙂 &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5eht81ylryxqmmknujcu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5eht81ylryxqmmknujcu.png" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And last thing 🤣&lt;/p&gt;

&lt;p&gt;Create a lot of bugs - that brings people in &lt;strong&gt;(I am kidding, of course.)&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  I invite you to register for my newsletter.
&lt;/h2&gt;

&lt;p&gt;This newsletter is good for you if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are considering open-sourcing your product (or building a new one).&lt;/li&gt;
&lt;li&gt;You are considering opening a by-product and open-source it (to reflect on your main product).&lt;/li&gt;
&lt;li&gt;You are in tech and want growth without the stars / without GitHub trending.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a 100% free newsletter (and always will be). Feel free to register at:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitroom.com/" rel="noopener noreferrer"&gt;https://gitroom.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86ywkzncq6erg44d6xy9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86ywkzncq6erg44d6xy9.gif" alt="In for tech" width="720" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How keepHQ got their first 2,000 stars!</title>
      <dc:creator>Nevo David</dc:creator>
      <pubDate>Tue, 05 Dec 2023 11:51:23 +0000</pubDate>
      <link>https://dev.to/github20k/how-keephq-got-their-first-2000-stars-l7i</link>
      <guid>https://dev.to/github20k/how-keephq-got-their-first-2000-stars-l7i</guid>
      <description>&lt;p&gt;I enjoyed talking to Tal, CEO and co-founder at &lt;a href="https://github.com/keephq/keep" rel="noopener noreferrer"&gt;Keep&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
It started as a CLI tool and, over time, became an alert aggregation tool.&lt;/p&gt;

&lt;p&gt;Today, they have almost 3,000 stars. &lt;strong&gt;You can watch the full video here:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/eykb1zbDwQo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  Starting out
&lt;/h2&gt;

&lt;p&gt;They have made a very basic alerting CLI tool and posted it on Hackernews - &lt;strong&gt;“Show HN:”&lt;/strong&gt; They went on a flight, and when they landed, &lt;strong&gt;they saw 600 stars&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hackernews.com?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=how-keephq-got-their-first-2-000-stars" rel="noopener noreferrer"&gt;Hackernews&lt;/a&gt; is an interesting website. It’s super ugly, gets a lot of traction, and is very hard to get in.&lt;/p&gt;

&lt;p&gt;I have seen and launched many products on Hackernews. While getting in for an article on Hackernews is hard, the &lt;strong&gt;“Show HN”&lt;/strong&gt; one is much easier.&lt;/p&gt;

&lt;p&gt;It’s usually a secret weapon since you can maybe do it once a year - it’s better to tie in with more channels to get a better chance to trend on GitHub.&lt;/p&gt;

&lt;p&gt;They created more tools, such as &lt;a href="https://www.gnip.io/?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=how-keephq-got-their-first-2-000-stars" rel="noopener noreferrer"&gt;gnip&lt;/a&gt;, and while this tool is not bringing a lot of traffic today, it did on its launch date.&lt;/p&gt;

&lt;p&gt;You see, for every side project you build, you can launch it in Hackernews (Show HN) and Product Hunt.&lt;/p&gt;

&lt;p&gt;My suggestion? &lt;strong&gt;Aim to release a new project once a month.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HACK:&lt;/strong&gt; Lately, some random person posted the &lt;strong&gt;Novu&lt;/strong&gt; organization page on Hackernews. I do not know how it got accepted, but it brought us 400 stars.&lt;br&gt;&lt;br&gt;
&lt;a href="https://news.ycombinator.com/item?id=38419513&amp;amp;utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=how-keephq-got-their-first-2-000-stars" rel="noopener noreferrer"&gt;Check the post here&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2o4h9mzs0u76ykpd3vy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2o4h9mzs0u76ykpd3vy.png" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Product Hunt with the community
&lt;/h2&gt;

&lt;p&gt;While Hackernews is super friendly with the open-source community (many early adopters), Product Hunt feels a bit more like indie-hacking / non developers’ tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal is to get as many upvotes as possible and reach the top of the list.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You should usually incorporate Product Hunt with other channels.&lt;br&gt;&lt;br&gt;
If you are starting and want stars - put your GitHub as your “Visit” URL.&lt;/p&gt;

&lt;p&gt;If you are a more prominent company and want to get more leads and book meetings, add your &lt;strong&gt;website URL.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the first launch, I would usually aim for the GitHub repository.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keep had a very small community but still managed to take 1st of the day.&lt;br&gt;&lt;br&gt;
The best founders don’t let luck guide them. &lt;strong&gt;Here is what they have done:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;They posted on their social media about their launch (like most people)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They try to contact as many people as possible to help them out.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They have built a secret weapon tool! &lt;a href="https://github.com/talboren/slackline?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=how-keephq-got-their-first-2-000-stars" rel="noopener noreferrer"&gt;Slackline&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwb6sili911d5uajrxks7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwb6sili911d5uajrxks7.png" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Slack-freakin’-line
&lt;/h2&gt;

&lt;p&gt;Tal showed me this tool a while ago, and I have used it ever since.&lt;br&gt;&lt;br&gt;
When you are a small startup, you must do the impossible to get from 0 to 1. &lt;strong&gt;Use all the possible options that you have.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Slackline is just for that. You can take any Slack group and DM every possible person in the channel.&lt;/p&gt;

&lt;p&gt;There are a few options for it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You can use it on your Slack channel to drive feedback for your product or get help from community members to do different things.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ask people for help on Product Hunt.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And while number 2 sounds a bit intrusive, it works - they got 1st of the day and the fame and glory 🎩&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixohvajn9t02lg0pw79e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixohvajn9t02lg0pw79e.png" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Using bounties
&lt;/h2&gt;

&lt;p&gt;You can put bounties on issues with &lt;a href="https://algora.io?utm_source=nevo.github20k.com&amp;amp;utm_medium=referral&amp;amp;utm_campaign=how-keephq-got-their-first-2-000-stars" rel="noopener noreferrer"&gt;Algora&lt;/a&gt;, to tell you that this will grow your community - probably not, but it will give you more credibility.&lt;/p&gt;

&lt;p&gt;If you are starting, Algora can help you get more contributors (in the contributors list) and make you look more credible.&lt;/p&gt;

&lt;p&gt;However, remember that contributors who come for money usually will not do the same things for free (not always).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/keephq/keep" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Star Keep on GitHub&lt;/a&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  I invite you to register for my newsletter.
&lt;/h2&gt;

&lt;p&gt;This newsletter is good for you if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are considering open-sourcing your product (or building a new one).&lt;/li&gt;
&lt;li&gt;You are considering opening a by-product and open-source it (to reflect on your main product).&lt;/li&gt;
&lt;li&gt;You are in tech and want growth without the stars / without GitHub trending.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a 100% free newsletter (and always will be). Feel free to register at:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitroom.com/" rel="noopener noreferrer"&gt;https://gitroom.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86ywkzncq6erg44d6xy9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86ywkzncq6erg44d6xy9.gif" alt="In for tech" width="720" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
