<?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: Phú</title>
    <description>The latest articles on DEV Community by Phú (@lkp).</description>
    <link>https://dev.to/lkp</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%2Fuser%2Fprofile_image%2F807538%2Fe1954dbe-0152-47f7-9369-2d858f3812fc.jpg</url>
      <title>DEV Community: Phú</title>
      <link>https://dev.to/lkp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lkp"/>
    <language>en</language>
    <item>
      <title>Hermes agent: Introduction</title>
      <dc:creator>Phú</dc:creator>
      <pubDate>Sun, 26 Apr 2026 02:37:22 +0000</pubDate>
      <link>https://dev.to/lkp/hermes-agent-introduction-c38</link>
      <guid>https://dev.to/lkp/hermes-agent-introduction-c38</guid>
      <description>&lt;h1&gt;
  
  
  Concept
&lt;/h1&gt;

&lt;p&gt;"Hermes Agent" is an open-source AI agent developed by Nous Research. It is described as an agent that runs continuously on your server, has long-term memory, can learn over time, connects to many chat platforms/tools, and supports browser automation. The project is released under the MIT license.&lt;/p&gt;

&lt;p&gt;Typically, this AI agent is meant to work as a real assistant. It can do more than just answer messages or connect to third-party services for information. It can manage your machine and even help deploy a web app, for example. It also has long-term memory to remember your habits and notes. In parallel, it can self-learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you repeat the same kind of task, it can proactively create a reusable skill so you do not need to manually re-derive the same steps every time.&lt;/li&gt;
&lt;li&gt;This reduces token usage for similar or repetitive work.&lt;/li&gt;
&lt;li&gt;It supports multiple gateways to mobile-friendly chat apps like Telegram and Discord, so you can operate your AI agent and machine from your phone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then refresh 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;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc    &lt;span class="c"&gt;# reload shell (or: source ~/.zshrc)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, &lt;code&gt;hermes&lt;/code&gt; command is available in your terminal. Next, you need to run &lt;code&gt;hermes setup&lt;/code&gt; to setup LLM for your hermes. You can choose quick setup or full setup up to you. In here, I choose quick setup to setup LLM only. &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%2Fs6e2k1ewwz19ndro71yk.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%2Fs6e2k1ewwz19ndro71yk.png" alt="Setup" width="729" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am using Minimax global, so I choose this option. &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%2Fd9c75rjjde8djfhmblrq.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%2Fd9c75rjjde8djfhmblrq.png" alt="Choose provider" width="800" height="597"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then it asks me to pass my api 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%2Fr6ivrc30ahqlvejoni6q.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%2Fr6ivrc30ahqlvejoni6q.png" alt="Pass api key" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, you need to choose model. &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%2Fgafsztkrdc6ng69v4pn5.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%2Fgafsztkrdc6ng69v4pn5.png" alt="Choose models" width="532" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, it asks to setup messaging platform or not. In this case, we skip this step. I will guide you to setup gateway later in this post.&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%2Fqzyf01gjqvhihuwpvaqg.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%2Fqzyf01gjqvhihuwpvaqg.png" alt=" " width="618" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then test with &lt;code&gt;hermes&lt;/code&gt;. If you see the expected prompt, the agent is installed successfully.&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%2Fwmuc6p9fy2ouzp3nrud8.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%2Fwmuc6p9fy2ouzp3nrud8.png" alt="Hermes Agent installed" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try asking what it is.&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%2Fvobpkm6dc9jgs0tvufvq.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%2Fvobpkm6dc9jgs0tvufvq.png" alt="Prompt asking identity" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  SOUL.md
&lt;/h1&gt;

&lt;p&gt;When using AI, we usually define a &lt;strong&gt;system prompt&lt;/strong&gt; so the model knows who it is and what it should do. This helps it stay focused on a specific type of work. For example, without a system prompt, if you ask for a simple "Hello World" program, the model may choose a language it is most familiar with. If you want it to always respond in a specific language, it may not comply consistently.&lt;/p&gt;

&lt;p&gt;A system prompt is a way to standardize this behavior across sessions. If you want it to act as a PHP expert, you can include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an expert in PHP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then every prompt will be interpreted in that context, and the model will try to answer with PHP-oriented decisions and knowledge.&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%2Fcamfd010qrhmx6c78b2l.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%2Fcamfd010qrhmx6c78b2l.png" alt="System Prompt" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Hermes Agent, there is &lt;strong&gt;&lt;code&gt;SOUL.md&lt;/code&gt;&lt;/strong&gt;, which plays a role similar to a system prompt. To optimize usage, set up &lt;code&gt;SOUL.md&lt;/code&gt; for the agent. By default it is located at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/.hermes/SOUL.md
&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%2Fzz1thqtbhs7gwz5b1zmr.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%2Fzz1thqtbhs7gwz5b1zmr.png" alt="Update SOUL.md" width="795" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I changed it to:&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%2Fqj7sjbpqbtlcl2zv140u.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%2Fqj7sjbpqbtlcl2zv140u.png" alt="Result" width="800" height="29"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, asking in that session, it now behaves as a PHP expert.&lt;br&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%2Frwz6exiobc4gq4rvnrxk.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%2Frwz6exiobc4gq4rvnrxk.png" alt="Workspace session behavior" width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Session
&lt;/h1&gt;

&lt;p&gt;At this point, I asked myself: why make it this complex? If I keep one session and ask questions from start to finish, it remembers previous context. Why bother with system prompts? Also, nobody has time to create a new session all the time.&lt;/p&gt;

&lt;p&gt;That can work initially: if you define the role in the first prompt, by prompt 100 it may still remember. But over time, behavior can degrade. When you cover too many topics in one long session, the model may become confused.&lt;/p&gt;

&lt;p&gt;Example: you work in &lt;code&gt;workspace1&lt;/code&gt;, ask it to save output to &lt;code&gt;result&lt;/code&gt;, then later switch to &lt;code&gt;workspace2&lt;/code&gt;. If you later ask again to save to &lt;code&gt;result&lt;/code&gt;, it may default to &lt;code&gt;workspace2/result&lt;/code&gt; because it inferred the active context changed. If you use two separate sessions, session 1 for &lt;code&gt;workspace1&lt;/code&gt; and session 2 for &lt;code&gt;workspace2&lt;/code&gt;, the same command will correctly map to each workspace.&lt;/p&gt;

&lt;p&gt;When working longer, the model also has a finite context window:&lt;br&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%2F0yd2eb00py3nkdh2nx9d.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%2F0yd2eb00py3nkdh2nx9d.png" alt="Context window" width="663" height="43"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That status bar shows the model is &lt;code&gt;minimax 2.7 highspeed&lt;/code&gt; with a context window of &lt;code&gt;204.8k&lt;/code&gt;. Every user prompt and model reply consumes part of that budget. The post shows one question-and-answer pair consuming about &lt;code&gt;11.7k&lt;/code&gt; tokens.&lt;/p&gt;

&lt;p&gt;As history grows beyond the window limit, the model compresses previous context. For example, when at around &lt;code&gt;200k&lt;/code&gt; tokens it may summarize context down to about &lt;code&gt;10k&lt;/code&gt; tokens. You can then continue with the summary, but the compressed memory loses detail. Some earlier details may no longer be present.&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%2F2om6ll1uuex5raxug1as.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%2F2om6ll1uuex5raxug1as.png" alt="Context window compress" width="800" height="107"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is why it is useful to keep a system prompt and open a fresh session for different tasks. You can start a new session using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/new
&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%2Folfibf2f9hkq0f16m95v.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%2Folfibf2f9hkq0f16m95v.png" alt=" " width="641" height="101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Prompt
&lt;/h1&gt;

&lt;p&gt;This is the prompt area used to communicate with the AI. This is where you issue commands or requests.&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%2Frkph94o6x9o2xc0f74q2.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%2Frkph94o6x9o2xc0f74q2.png" alt=" " width="800" height="66"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example I asked it to summarize a YouTube video. Hermes Agent shows each step it performs, such as invoking a skill and opening the browser.&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%2F53kz2umj5t3lduqgqh0g.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%2F53kz2umj5t3lduqgqh0g.png" alt=" " width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is the result:&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%2Fud24ucalf3h2606fj0s0.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%2Fud24ucalf3h2606fj0s0.png" alt=" " width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Gateway
&lt;/h1&gt;

&lt;p&gt;If you want to use your AI agent through chat apps (for example Telegram or Discord), either for team use or for personal use, set up a gateway.&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%2Fqamc4eyz9aczseqw50pe.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%2Fqamc4eyz9aczseqw50pe.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used Telegram as an example. First, use Telegram BotFather to create a bot. It gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a bot access handle (to open your bot)&lt;/li&gt;
&lt;li&gt;the bot token&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%2Fzrt6u8al3s14eateg8y2.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%2Fzrt6u8al3s14eateg8y2.png" alt=" " width="654" height="699"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To configure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hermes gateway setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then choose the Telegram gateway, paste the bot token into &lt;code&gt;bot token&lt;/code&gt;, and set &lt;code&gt;allow user id&lt;/code&gt; using &lt;code&gt;@userinfobot&lt;/code&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%2Fa145mlrgniqzf1ox2l4h.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%2Fa145mlrgniqzf1ox2l4h.png" alt=" " width="772" height="259"&gt;&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%2F0kxb8qjd65v0dq8m6u1r.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%2F0kxb8qjd65v0dq8m6u1r.png" alt=" " width="800" height="562"&gt;&lt;/a&gt;&lt;br&gt;
If your team should all be able to chat with the bot, enable &lt;strong&gt;open access&lt;/strong&gt;. If you want manual approval first, use &lt;strong&gt;Use DM pairing&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%2Fgrpj9deodn0srvd8u5ym.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%2Fgrpj9deodn0srvd8u5ym.png" alt=" " width="628" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this step, you can choose open access to allow any user in this channel can chat with hermes agent. Otherwise, you choose pairing dm. This one, you can approve which message bot will answer, which one it will not 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%2F53zhce359tgk13uaf4sc.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%2F53zhce359tgk13uaf4sc.png" alt=" " width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For gateway mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Option 1: manual mode. You run &lt;code&gt;hermes gateway start&lt;/code&gt; each time.&lt;/li&gt;
&lt;li&gt;Option 2: service mode. The gateway runs automatically as a background service.&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%2Fwr5jmpcx9e48u2hzwyhd.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%2Fwr5jmpcx9e48u2hzwyhd.png" alt=" " width="800" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Test it by running the same brief video task, this time via Telegram.&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%2Ft5mqqqh3xv2j9z6aqfwq.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%2Ft5mqqqh3xv2j9z6aqfwq.png" alt=" " width="749" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Result:&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%2Flihnosoc28vvdahvd7qv.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%2Flihnosoc28vvdahvd7qv.png" alt=" " width="744" height="962"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;That’s a brief first look. The next post can cover more topics in depth. If you need help, leave a comment.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>bot</category>
    </item>
    <item>
      <title>Nextjs: Introduction</title>
      <dc:creator>Phú</dc:creator>
      <pubDate>Thu, 02 Feb 2023 01:41:03 +0000</pubDate>
      <link>https://dev.to/lkp/nextjs-introduction-hej</link>
      <guid>https://dev.to/lkp/nextjs-introduction-hej</guid>
      <description>&lt;h2&gt;
  
  
  What is Nextjs?
&lt;/h2&gt;

&lt;p&gt;Acorrding to the official documentation, Next.js is a flexible React framework that gives you building blocks to create fast web applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Nextjs?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Difference rendering techniques
&lt;/h3&gt;

&lt;p&gt;Server Side Rendering is technique when you want to get new data from server, client will pass necessary params to server and get the whole html from server. With this approach, our app is not reactive. When you search something, filter something, click something, it will reload the whole html. It is not very friendly when you have a lot of data and user need to spend time to look at blank screen while your site is loading data. But it is good for SEO cause it always return html and google bot know what is your site about. &lt;/p&gt;

&lt;p&gt;Client Side Rendering is technique when you pass params to server from client, you will get data in json format from server. For that reason, you will save your bandwidth, your page will load faster and it will be more reactive. Nowadays, good frameworks like React, Vue, Angular do these things really well. It also handle or at least, give you a tool or a clear guide transpile to work with old browser, bundling, minifying, splitting. It will make your app faster and more compatible. However, big disadvantage in this approach is that it is hard to SEO. Why? When you load a page, in React case, you only have an html element with id is root, after that React will handle to render the rest. And google bot just see the html element before React render the rest so it only see your page have an html element with id is root. For that reason, it have no idea what is your site about and lower your page rank.&lt;/p&gt;

&lt;p&gt;Static Site Generation is technique to generate html file in build time. For example, you finish to implement your about page, you build your project, it will generate html file of about page and store in your project. So when user want to view your about page, the site will return that file instead of calling data from server. Then, it will much faster. It is very good if you don't have many changes for your page. Like about page, login page, landing page,... you won't often change or don't often have a new data so these pages is good to use SSG. &lt;/p&gt;

&lt;p&gt;Usually, you don't have all these technique in your application cause no framework support all these rendering technique yet until Nextjs. Before Nextjs, if you want SSR, you may go with pure PHP, Laravel + Blade or Symfony + Twig. If you want CSR, definitely go with React, Vue or Angular and SSG will a place where you want to use gatsby. In Nextjs, you can choose the rendering technique you want. Thus, you can have page A with SSR, page B with CSR, page C with SSG. How cool is that?&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;To boost your site faster, you need to care about many things like code splitting, minifying files, image optimaztion, the way to get assets and many more. Thankfully, with Nextjs, you don't need to care much about this. If you use correct component which are provide by Nextjs, it will do all the heavy job for you. Small example is that when you have an image on your site, you need to take care very 2 basic things. First of all, you need to have difference size of that image for difference viewport. Secondly, you want your page only load that image when user near to it, so you will have very long page and of course, you don't want to load image at the end of that page where user don't see it when the page is loaded. When user scroll down near to the end, that image will be load. Therefore, to solve these two problems, you need add srcset and apply lazy load to your image. With simple component &lt;code&gt;Image&lt;/code&gt;, it handle these two things automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routing
&lt;/h3&gt;

&lt;p&gt;In Nextjs, it route base on file. In my opinion, it is more friendly for routing base on file. In case I want to find component for route &lt;code&gt;/posts/&lt;/code&gt;, I can easily know that I need to go to index file in posts folder. No need to go to see which component is used for that route.&lt;/p&gt;

&lt;h3&gt;
  
  
  SEO
&lt;/h3&gt;

&lt;p&gt;Nextjs provide a Head component. With this component, you can always add description, title, meta tag on header in Nextjs. For that reason, it will be better for SEO.&lt;/p&gt;

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

&lt;p&gt;That's is a short introduction to nextjs. In recap, it provides us many ways to render page, help we improve performance, routing base on file, provide us a way to SEO and much more.&lt;/p&gt;

</description>
      <category>cryptocurrency</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Multiple authentication in Laravel 9</title>
      <dc:creator>Phú</dc:creator>
      <pubDate>Mon, 16 Jan 2023 01:46:52 +0000</pubDate>
      <link>https://dev.to/lkp/multiple-authentication-in-laravel-9-2mfk</link>
      <guid>https://dev.to/lkp/multiple-authentication-in-laravel-9-2mfk</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;In a basic web app, we usually have two parts, app and cms. App is for user to use and cms for staff to manage content in that system. So to design this web app, we need to have a role. User with role admin can access cms site and user without role admin cannot access cms. But what if you want to use 2 difference models for security, for performance? How can we authenticate with 2 difference models?&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduce app
&lt;/h2&gt;

&lt;p&gt;This is a web app have two parts, app and CMS. Model Staff can only access CMS part and model User can only access app part. Since Laravel have default guard authentication for User model, we will discuss more about Staff model&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure guard
&lt;/h2&gt;

&lt;p&gt;First of all, you need to add new guard to existing guard in &lt;code&gt;config/auth.php&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   'guards' =&amp;gt; [
        ...
        'staff' =&amp;gt; [
            'driver' =&amp;gt; 'session',
            'provider' =&amp;gt; 'staffs',
        ],
    ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this configuration, I add new guard name &lt;strong&gt;staff&lt;/strong&gt;, this guard use driver is session and provider name staffs. Currently, we do not have any provider name staffs, so let's define it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    'providers' =&amp;gt; [
        ...
        'staffs' =&amp;gt; [
            'driver' =&amp;gt; 'eloquent',
            'model' =&amp;gt; App\Models\Staff::class,
        ],
    ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this definition, we define provider name staffs using driver eloquent and model we want to use is &lt;code&gt;App\Models\Staff&lt;/code&gt;. Last but not least, we need to configure password part so we can reset password with Staff model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    'passwords' =&amp;gt; [
        ...
        'staffs' =&amp;gt; [
            'provider' =&amp;gt; 'staffs',
            'table' =&amp;gt; 'staff_password_resets',
            'expire' =&amp;gt; 60,
            'throttle' =&amp;gt; 60,
        ],
    ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is quite simple. We use provider name staffs, table is staff_password_resets, expire and throttle is 60 minutes. Since we use staff_password_resets to reset password then remember to migrate it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Ensure
&lt;/h2&gt;

&lt;p&gt;After configuration, we need to ensure these things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Migrate table for reset password
It will look like this one:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function up()
    {
        Schema::create('staff_password_resets', function (Blueprint $table) {
            $table-&amp;gt;string('email')-&amp;gt;index();
            $table-&amp;gt;string('token');
            $table-&amp;gt;timestamp('created_at')-&amp;gt;nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('staff_password_resets');
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Have Staff model
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class Staff extends Authenticatable
{
    use HasApiTo   'guards' =&amp;gt; [
        ...
        'staff' =&amp;gt; [
            'driver' =&amp;gt; 'session',
            'provider' =&amp;gt; 'staffs',
        ],
    ],kens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array&amp;lt;int, string&amp;gt;
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array&amp;lt;int, string&amp;gt;
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array&amp;lt;string, string&amp;gt;
     */
    protected $casts = [
        'email_verified_at' =&amp;gt; 'datetime',
    ];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Have data in table&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%2F1zjpgyqtmm1j017f0uda.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%2F1zjpgyqtmm1j017f0uda.png" alt="Data in Staff table" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use new guard
&lt;/h2&gt;

&lt;p&gt;Let's try out new guard. In login logic, you will have code like this:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
Auth::attempt($this-&amp;gt;only('email', 'password'), $this-&amp;gt;boolean('remember'))&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
This one will not work because it will use default guard which is user guard. If we want to use new guard, we need to explicitly use it. Change it to this:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
Auth::guard('staff)-&amp;gt;attempt($this-&amp;gt;only('email', 'password'), $this-&amp;gt;boolean('remember'))&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
So this one tell Laravel to use guard name staff instead of default. Try to login and check the session, you will see that we login successfully and have a session. However, we cannot go to page which ask for authentication. Why? Cause in these pages, we still not use new guard yet. This is my route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route::get('/dashboard', function () {
    return view('dashboard');
})-&amp;gt;middleware(['auth', 'verified'])-&amp;gt;name('dashboard');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take a look at &lt;code&gt;middleware(['auth', 'verified'])&lt;/code&gt;. It will go to auth and verified middlewar before run callback in Route::get. Verified middleware simply check verified_at colume in table is null or not and auth middleware check that user is authenticated or not. Cause we just use auth middleware then again, it use default guard which is user guard. We need to tell it to use staff guard by passing parameter to middleware. Change it to this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route::get('/dashboard', function () {
    return view('dashboard');
})-&amp;gt;middleware(['auth:staff', 'verified'])-&amp;gt;name('dashboard');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we change to use auth middleware with staff guard instead of user guard. Then try to login again and you can access &lt;code&gt;/dashboard&lt;/code&gt; route:&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%2Fpxmii0wuj8moegbrpglv.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%2Fpxmii0wuj8moegbrpglv.png" alt="Dashboard after login" width="800" height="176"&gt;&lt;/a&gt;&lt;br&gt;
Perfection. You rock.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Lastly, we need to test to make sure that user in User table cannot use their data to login to &lt;code&gt;/dashboard&lt;/code&gt;. This is user in User table:&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%2Fkpb117vgndts953k93ln.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%2Fkpb117vgndts953k93ln.png" alt="User in User table" width="800" height="152"&gt;&lt;/a&gt;&lt;br&gt;
Try to login using this credential:&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%2Fn6gioim0buecb9gl3exe.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%2Fn6gioim0buecb9gl3exe.png" alt="Try to login with User table" width="800" height="625"&gt;&lt;/a&gt;&lt;br&gt;
Failed. Great, this is what we expect, it cannot find any records cause when using staff guard, it just only take a look in Staff table. That's why, it did not found any records. That's all. Thanks for reading.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webcomponents</category>
      <category>frontend</category>
      <category>design</category>
    </item>
    <item>
      <title>VIM: Introduction</title>
      <dc:creator>Phú</dc:creator>
      <pubDate>Sat, 16 Jul 2022 16:02:36 +0000</pubDate>
      <link>https://dev.to/lkp/vim-introduction-2dgl</link>
      <guid>https://dev.to/lkp/vim-introduction-2dgl</guid>
      <description>&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%2F5iu1ag4xxvhd9vi8uou9.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%2F5iu1ag4xxvhd9vi8uou9.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Video for this tutorial here:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/BNx7tgDdTi0" rel="noopener noreferrer"&gt;https://youtu.be/BNx7tgDdTi0&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is VIM?
&lt;/h2&gt;

&lt;p&gt;First of all, let’s talk about vi (pronouce vee-eye). Vi editor is a super popular editor in linux because it help you to increase your productivity by just using your keyboard. For that reason, you don’t need to use mouse when you want to move around in your file, you want to copy paste character or word, etc.&lt;/p&gt;

&lt;p&gt;That’s it for vi and VIM is VI iMproved. So VIM is an improvement version of vi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open VIM
&lt;/h2&gt;

&lt;p&gt;So how can we enter the VIM world. Firstly, you need to have VIM in your computer. If you do not have VIM, then go to install it first. For Ubuntu, you can run this command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt install vim&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In Arch based distro:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo pacman -S vim&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After you have vim in your computer then open your terminal and type vim . The screen you are seeing is VIM welcome screen. It will explain to you what is VIM, version of VIM, VIM’s author, license and some helpful command, especially quit command. Why we need to pay attention to quit command? Because some people use VIM for many years just because they have no idea how to quit VIM. Don’t be that guy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quit VIM
&lt;/h2&gt;

&lt;p&gt;As I say, quit VIM is a very important thing. Thus, to quit VIM, type ESC , after that type :q! . It means quit VIM without saving anything. Another way, you can type ZZ and you can quit VIM, too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write something, save and quit
&lt;/h2&gt;

&lt;p&gt;Now, open VIM again by typing vim . Type i , you will see INSERT message on the bottom left of your screen. In this mode, you can type anything you want. So let’s type some code: &amp;lt;?php echo 'Hello World'; . Save it by type ESC and type :w filename , it means save this file whose name is filename . In this case, I want it to be index.php then I will type :w index.php and type :q to exit. Next, check files, you will see your new file name index.php . Let’s run it if you have PHP in your computer, if not then skip it php index.php . Hooray, you can open VIM, type something and save it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small tip and trick
&lt;/h2&gt;

&lt;p&gt;I have a quicker way to name your file. When you open vim, you can type your filename after vim command. For example, vim filename , it means you start to write on file whose name is filename. Then when you want to save it, you just need to run command :w . In addition, if you want to save and quit, you can type :wq , it means write this file and quit.&lt;/p&gt;

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

&lt;p&gt;In this article, we learnt how to open, write, save and quit VIM. See you next time. Until that, I hope you happy with VIM. See ya!&lt;/p&gt;

</description>
      <category>vim</category>
      <category>programming</category>
      <category>editor</category>
    </item>
  </channel>
</rss>
