<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://blog.tomaszdunia.pl/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.tomaszdunia.pl/" rel="alternate" type="text/html" /><updated>2026-03-10T13:58:47+00:00</updated><id>https://blog.tomaszdunia.pl/feed.xml</id><title type="html">Tomasz Dunia - Blog</title><subtitle>Blog o wszystkim - przemyślenia, poradniki, projekty otwarto-źródłowe, praca, self-hosting, seriale, filmy / Blog about everything - thoughts, tutorials, open-source projects, work, self-hosting, series, movies</subtitle><author><name>Tomasz Dunia</name></author><entry><title type="html">Is Office.EU a scam? [ENG 🇬🇧]</title><link href="https://blog.tomaszdunia.pl/officeeu-eng/" rel="alternate" type="text/html" title="Is Office.EU a scam? [ENG 🇬🇧]" /><published>2026-03-08T00:00:00+00:00</published><updated>2026-03-08T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/officeeu-eng</id><content type="html" xml:base="https://blog.tomaszdunia.pl/officeeu-eng/"><![CDATA[<p><a href="https://blog.tomaszdunia.pl/officeeu/">🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post</a></p>

<p>Table of contents:</p>
<ul id="markdown-toc">
  <li><a href="#introduction---an-ode-to-wykop" id="markdown-toc-introduction---an-ode-to-wykop">Introduction - An Ode to Wykop</a></li>
  <li><a href="#what-is-officeeu-and-what-does-it-offer" id="markdown-toc-what-is-officeeu-and-what-does-it-offer">What is Office.EU and what does it offer?</a></li>
  <li><a href="#who-is-behind-it" id="markdown-toc-who-is-behind-it">Who is behind it?</a></li>
  <li><a href="#exact-product-definition-its-not-libreoffice" id="markdown-toc-exact-product-definition-its-not-libreoffice">Exact product definition (It’s not LibreOffice!)</a></li>
  <li><a href="#repackaging-ready-made-open-source-tools" id="markdown-toc-repackaging-ready-made-open-source-tools">Repackaging ready-made open-source tools</a></li>
  <li><a href="#but-could-it-be-a-valid-initiative" id="markdown-toc-but-could-it-be-a-valid-initiative">But could it be a valid initiative?</a></li>
  <li><a href="#what-instead-of-officeeu-proven-european-alternatives" id="markdown-toc-what-instead-of-officeeu-proven-european-alternatives">What instead of Office.EU? Proven European alternatives</a></li>
</ul>

<h2 id="introduction---an-ode-to-wykop">Introduction - An Ode to Wykop</h2>

<p>Anyone who didn’t grow up under a rock in Poland knows what Wykop is like. Reading the comments, let alone participating there, requires a truly strong psyche and an unwavering sense of self-worth. However, I must admit that I subscribe to Wykop’s front page to know what’s going on, and I like checking this channel in my RSS reader because I always stumble upon something interesting. That’s exactly what happened one Sunday afternoon. I came across this particular find: <strong><em><a href="https://wykop.pl/link/7902951/powstaje-nowy-europejski-pakiet-biurowy-typu-open-source">A new European open-source office suite is being created</a></em></strong>. Sounds interesting, it’s just a pity that very little of it adds up.</p>

<h2 id="what-is-officeeu-and-what-does-it-offer">What is Office.EU and what does it offer?</h2>

<p>The topic caused quite a buzz because <strong><a href="https://office.eu/">Office.EU</a></strong> positions itself as a <strong>100% European alternative</strong> to services from giants like Microsoft or Google. The main driving force behind this service’s marketing is the promise of full <strong>digital sovereignty</strong>. It’s about making European companies and citizens independent of American corporations and their laws (e.g., the <em>Cloud Act</em>, which theoretically allows US agencies to access data stored by American companies, even if it is physically located in Europe). It sounds like a remedy for the ailments of the modern Internet, but it’s worth taking a closer look.</p>

<h2 id="who-is-behind-it">Who is behind it?</h2>

<p>Let’s start with the basics, meaning the company itself. The operator of the service is a Dutch company, <strong>EUfforic Europe BV</strong> (commercial register number: 98746243). At the head of the project, as CEO, is Maarten Roelfs, whose <a href="https://www.linkedin.com/in/maartenroelfs/">LinkedIn profile</a> can be found without any problem. A typical guy whose profession is being a CEO. We dig further and here comes the first clash - the official address of the company is Dr. Kuyperstraat 10-A in The Hague. A quick glance at the web and we know that it’s simply a coworking space and a <strong>virtual office</strong>. Although this is a popular practice, in the case of a loudly announced “alternative to Google,” the lack of its own physical facilities makes things <strong>start to smell a bit fishy</strong>.</p>

<h2 id="exact-product-definition-its-not-libreoffice">Exact product definition (It’s not LibreOffice!)</h2>

<p>Many people online <strong>mistakenly compare Office.EU to LibreOffice</strong>. On the one hand, looking for a correlation is spot on, because <strong>LibreOffice is a European tool</strong>, despite its convoluted history. It is worth reminding here that the predecessor of this program – <strong>OpenOffice</strong> – was once <strong>taken over by the American corporation</strong> Oracle. Fearing a dictate from the US, the developer community created a branch (a so-called fork) and established the independent <strong>The Document Foundation in Germany</strong>. That’s how the <strong>secure and free LibreOffice</strong> was created.</p>

<p>Beyond this aspect, however, the comparison is misguided, because we are talking about <strong>completely different categories of products</strong>. LibreOffice is a <strong>locally installed office suite</strong>, consisting of a word processor, spreadsheet, presentation tool, and a few other components. It is a free and open-source equivalent of Microsoft Office. Office.EU is a completely different story, because it is an <strong>entire cloud ecosystem (SaaS)</strong>. It includes a shared calendar, virtual drive, e-mail, messenger, and integrated online document editors. Hence, the correct comparison here would be <strong>Microsoft 365</strong> and <strong>Google Workspace</strong>.</p>

<h2 id="repackaging-ready-made-open-source-tools">Repackaging ready-made open-source tools</h2>

<p>And here we come to the most important point, which ultimately unmasks the Office.EU revolution. <strong>The company did not create any innovative, proprietary code.</strong> The platform is simply the popular and free <strong>Nextcloud Hub</strong> in disguise. This shouldn’t be a surprise, because you can find a mention of this on the project’s official website.</p>

<p>The creators configured ready-made open-source tools (Nextcloud for drive and service management + OnlyOffice/Collabora for editing documents), slapped their logo on it, and are selling it as their own product. They physically keep the data with external providers – they themselves officially declare using the infrastructure of the German company Hetzner. <strong>They are pushing to people as a paid service something that any moderately tech-savvy person can set up for free</strong> on their own home equipment or a cheap VPS server, thereby gaining 100% control over their files, without the intermediation of another virtual entity of questionable credibility.</p>

<h2 id="but-could-it-be-a-valid-initiative">But could it be a valid initiative?</h2>

<p>You have to hand it to them: the initiative has partially valid foundations. <strong>Fighting for digital sovereignty and building alternatives to the behemoths from across the ocean is a good and necessary direction for Europe</strong>.</p>

<p>However, personally, I think that in this specific edition, <strong>the project is just a blatant cash grab</strong>, and one executed along the path of least resistance. They took ready-made, free tools created by enthusiasts, wrapped them in a different graphic design, bought server space, and are selling them to the naive under the guise of a “great, proven, European product” that supposedly cares about our privacy. We are dealing here with a classic <strong>parvenu</strong> (that is, an upstart, a person without real achievements and class who wants to quickly gain a position), feeding off the fruits of the hard, unpaid labor of other programmers from the open-source movement.</p>

<h2 id="what-instead-of-officeeu-proven-european-alternatives">What instead of Office.EU? Proven European alternatives</h2>

<p>In my case, it looks like this:</p>

<ul>
  <li>
    <p>locally, as an office suite, I obviously use <strong>LibreOffice</strong>,</p>
  </li>
  <li>
    <p>whereas, as an analogous solution to Office.EU, I have my own <strong>Nextcloud instance</strong>, which I additionally share with my family.</p>
  </li>
</ul>

<p>Normally, that would close the topic for me, but I felt obliged to check if there really isn’t any European solution offering what Office.EU does. And you know what? It turns out that a quick browse of the Internet revealed that <strong>you can easily find three</strong> (and probably even more) alternatives.</p>

<p>Instead of trusting startups registered in virtual offices, it’s much better (and safer) to bet on proven European companies that have been building their own infrastructure and reputation for years:</p>

<ul>
  <li>
    <p><a href="https://www.infomaniak.com/pl/kdrive"><strong>Infomaniak kDrive</strong></a> – A Swiss leader owning its own ecological data centers. A powerful and stable service with a drive, e-mail, and documents.</p>
  </li>
  <li>
    <p><a href="https://mailbox.org/"><strong>Mailbox.org</strong></a> – A highly regarded German provider. They provide a legendarily secure e-mail and a cloud office suite (based on Open-Xchange).</p>
  </li>
  <li>
    <p><a href="https://proton.me/drive"><strong>Proton Drive</strong></a> – A Swiss company (creators of ProtonMail) that offers services with full end-to-end encryption (E2EE).</p>
  </li>
</ul>]]></content><author><name>Tomasz Dunia</name></author><category term="shorts" /><category term="thoughts" /><category term="office-eu" /><category term="libreoffice" /><category term="openoffice" /><category term="eu" /><category term="europe" /><category term="eufforic" /><category term="maarten-roelfs" /><category term="microsoft-365" /><category term="google-workspace" /><category term="nextcloud" /><category term="saas" /><category term="onlyoffice" /><category term="collabora" /><category term="hetzner" /><category term="infomaniak-kdrive" /><category term="mailbox-org" /><category term="proton-drive" /><summary type="html"><![CDATA[🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/officeeu.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/officeeu.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Czy Office.EU to scam?</title><link href="https://blog.tomaszdunia.pl/officeeu/" rel="alternate" type="text/html" title="Czy Office.EU to scam?" /><published>2026-03-08T00:00:00+00:00</published><updated>2026-03-08T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/officeeu</id><content type="html" xml:base="https://blog.tomaszdunia.pl/officeeu/"><![CDATA[<p><a href="https://blog.tomaszdunia.pl/officeeu-eng/">🇵🇱-&gt;🇬🇧 Go to english version of this post / Przejdź do angielskiej wersji tego wpisu</a></p>

<p>Spis treści:</p>
<ul id="markdown-toc">
  <li><a href="#wstęp---oda-do-wykopu" id="markdown-toc-wstęp---oda-do-wykopu">Wstęp - Oda do Wykopu</a></li>
  <li><a href="#czym-jest-officeeu-i-co-oferuje" id="markdown-toc-czym-jest-officeeu-i-co-oferuje">Czym jest Office.EU i co oferuje?</a></li>
  <li><a href="#kto-za-tym-stoi" id="markdown-toc-kto-za-tym-stoi">Kto za tym stoi?</a></li>
  <li><a href="#dokładna-definicja-produktu-to-nie-jest-libreoffice" id="markdown-toc-dokładna-definicja-produktu-to-nie-jest-libreoffice">Dokładna definicja produktu (To nie jest LibreOffice!)</a></li>
  <li><a href="#przepakowanie-gotowych-narzędzi-open-source" id="markdown-toc-przepakowanie-gotowych-narzędzi-open-source">Przepakowanie gotowych narzędzi open-source</a></li>
  <li><a href="#czy-to-może-jednak-słuszna-inicjatywa" id="markdown-toc-czy-to-może-jednak-słuszna-inicjatywa">Czy to może jednak słuszna inicjatywa?</a></li>
  <li><a href="#co-zamiast-officeeu-sprawdzone-europejskie-alternatywy" id="markdown-toc-co-zamiast-officeeu-sprawdzone-europejskie-alternatywy">Co zamiast Office.EU? Sprawdzone europejskie alternatywy</a></li>
</ul>

<h2 id="wstęp---oda-do-wykopu">Wstęp - Oda do Wykopu</h2>

<p>Ten kto nie wychował się pod kamieniem ten wie jaki jest Wykop. Czytanie komentarzy, a już udzielanie się tam wymaga naprawdę silnej psychiki i niezachwianego poczucia własnej wartości. Jednakże muszę przyznać, że subskrybuję główną Wykopu, żeby wiedzieć co w trawie piszczy i lubię zaglądać do tego kanału na moim czytniku RSS, bo zawsze trafię tam na coś ciekawe. Tak też stało się pewnego niedzielnego popołudnia. Natrawiłem na to oto znalezisko <strong><em><a href="https://wykop.pl/link/7902951/powstaje-nowy-europejski-pakiet-biurowy-typu-open-source">
Powstaje nowy europejski pakiet biurowy typu open source</a></em></strong>. Brzmi ciekawe szkoda tylko, że niewiele się tu zgadza.</p>

<h2 id="czym-jest-officeeu-i-co-oferuje">Czym jest Office.EU i co oferuje?</h2>

<p>Temat wywołał spory szum, ponieważ <strong><a href="https://office.eu/">Office.EU</a></strong> pozycjonuje się jako <strong>w 100% europejska alternatywa</strong> dla usług takich gigantów jak Microsoft czy Google. Głównym motorem napędowym marketingu tej usługi jest obietnica pełnej <strong>cyfrowej suwerenności</strong>. Chodzi o uniezależnienie europejskich firm i obywateli od amerykańskich korporacji oraz tamtejszego prawa (np. <em>Cloud Act</em>, które teoretycznie pozwala służbom USA na wgląd w dane przechowywane przez amerykańskie firmy, nawet jeśli fizycznie znajdują się one w Europie). Brzmi to jak remedium na bolączki współczesnego Internetu, ale warto przyjrzeć się temu bliżej.</p>

<h2 id="kto-za-tym-stoi">Kto za tym stoi?</h2>

<p>Zacznijmy od podstaw, czyli samej firmy. Operatorem usługi jest holenderska spółka <strong>EUfforic Europe BV</strong> (numer w rejestrze handlowym: 98746243). Na czele projektu, jako CEO, stoi Maarten Roelfs, którego <a href="https://www.linkedin.com/in/maartenroelfs/">profil na LinkedIn</a> można znaleźć bez problemu. Typowy facet, który z zawodu jest prezesem. Sprawdzamy dalej i tu pojawia się pierwszy zgrzyt - oficjalnym adresem spółki jest Dr. Kuyperstraat 10-A w Hadze. Szybki rzut oka w sieć i wiemy, że to po prostu przestrzeń coworkingowa i <strong>biuro wirtualne</strong>. Choć to popularna praktyka, w przypadku szumnie zapowiadanej “alternatywy dla Google’a” brak własnego, fizycznego zaplecza sprawia, że coś tu <strong>zaczyna lekko śmierdzieć</strong>.</p>

<h2 id="dokładna-definicja-produktu-to-nie-jest-libreoffice">Dokładna definicja produktu (To nie jest LibreOffice!)</h2>

<p>Wiele osób w sieci <strong>błędnie porównuje Office.EU do LibreOffice</strong>. Z jednej strony szukanie korelacji jest trafione, bo <strong>LibreOffice jest europejskim narzędziem</strong>, mimo swojej zawiłej historii. Warto tu przypomnieć, że pierwowzór tego programu – <strong>OpenOffice</strong> – został swego czasu <strong>przejęty przez amerykańską korporację</strong> Oracle. W obawie przed dyktatem z USA, społeczność programistów stworzyła odłam (tzw. fork) i powołała niezależną fundację <strong>The Document Foundation w Niemczech</strong>. Tak powstał <strong>bezpieczny i darmowy LibreOffice</strong>.</p>

<p>Poza tym aspektem porównanie jest jednak chybione, ponieważ mówimy o <strong>zupełnie innych kategoriach produktów</strong>. LibreOffice to <strong>pakiet biurowy instalowany lokalnie</strong>, składający się z edytora tekstu, arkusza kalkulacyjnego, narzędzia do tworzenia prezentacji i kilku innych komponentów. To darmowy i otwartoźródłowy odpowiednik Microsoft Office. Office.EU to zupełnie inna bajka, bo jest to <strong>cały ekosystem chmurowy (SaaS)</strong>. W jego skład wchodzi współdzielony kalendarz, wirtualny dysk, poczta e-mail, komunikator oraz zintegrowane edytory dokumentów online. Stąd prawidłowym porównaniem będą tutaj <strong>Microsoft 365</strong> i <strong>Google Workspace</strong>.</p>

<h2 id="przepakowanie-gotowych-narzędzi-open-source">Przepakowanie gotowych narzędzi open-source</h2>

<p>I tutaj dochodzimy do najważniejszego punktu, który ostatecznie demaskuje rewolucję Office.EU. <strong>Firma nie stworzyła żadnego innowacyjnego, autorskiego kodu.</strong> Platforma to po prostu popularny i darmowy <strong>Nextcloud Hub</strong> w przebraniu. Nie powinno to być zaskoczenie, bo da się znaleźć o tym wzmiankę na oficjalnej stronie projektu.</p>

<p>Twórcy skonfigurowali gotowe narzędzia open-source (Nextcloud do zarządzania dyskiem i usługami + OnlyOffice/Collabora do edycji dokumentów), nałożyli na to swoje logo i sprzedają jako własny produkt. Dane fizycznie trzymają u zewnętrznych dostawców – oni sami oficjalnie deklarują korzystanie z infrastruktury niemieckiej firmy Hetzner. <strong>Wciskają ludziom jako płatną usługę coś, co każda średnio ogarnięta osoba może postawić sobie za darmo</strong> na własnym domowym sprzęcie lub tanim serwerze VPS, zyskując dzięki temu 100% władzy nad swoimi plikami, bez pośrednictwa kolejnego, wirtualnego podmiotu o wątpliwej wiarygodności.</p>

<h2 id="czy-to-może-jednak-słuszna-inicjatywa">Czy to może jednak słuszna inicjatywa?</h2>

<p>Trzeba oddać im jedno: inicjatywa ma częściowo słuszne fundamenty. <strong>Walka o cyfrową suwerenność i budowanie alternatyw dla molochów zza oceanu to dobry i potrzebny kierunek dla Europy</strong>.</p>

<p>Jednakże osobiście uważam, że w tym konkretnym wydaniu <strong>projekt to zwykły skok na kasę</strong>, i to zrealizowany po linii najmniejszego oporu. Wzięli gotowe, darmowe narzędzia stworzone przez pasjonatów, opakowali w inną szatę graficzną, wykupili miejsce na serwerze i sprzedają naiwnym pod płaszczykiem “wielkiego, sprawdzonego, europejskiego produktu”, który rzekomo dba o naszą prywatność. Mamy tu do czynienia z klasycznym <strong>parweniuszem</strong> (czyli dorobkiewiczem, osobą bez realnego dorobku i klasy, która szybko chce zyskać pozycję), żerującym na owocach ciężkiej, nieodpłatnej pracy innych programistów z ruchu open-source.</p>

<h2 id="co-zamiast-officeeu-sprawdzone-europejskie-alternatywy">Co zamiast Office.EU? Sprawdzone europejskie alternatywy</h2>

<p>W moim przypadku wygląda to tak:</p>

<ul>
  <li>
    <p>lokalnie jako pakiet biurowy wykorzystuję oczywiście <strong>LibreOffice</strong>,</p>
  </li>
  <li>
    <p>natomiast jako rozwiązanie analogiczne do Office.EU mam swoją własną <strong>instancję Nextcloud</strong>, którą w dodatku udostępniam rodzinie.</p>
  </li>
</ul>

<p>Normalnie zamknęłoby to dla mnie temat, ale poczułem się w obowiązku sprawdzić, czy faktycznie nie istnieje żadne europejskie rozwiązanie oferujące to, co Office.EU. I wiecie co? Okazuje się, że już szybki przegląd Internetu ujawnił, że <strong>bez problemu można znaleźć trzy</strong> (i pewnie nawet więcej) alternatywy.</p>

<p>Zamiast ufać startupom zarejestrowanym w wirtualnych biurach, znacznie lepiej (i bezpieczniej) postawić na sprawdzone europejskie firmy, które od lat budują własną infrastrukturę i reputację:</p>

<ul>
  <li>
    <p><a href="https://www.infomaniak.com/pl/kdrive"><strong>Infomaniak kDrive</strong></a> – Szwajcarski lider posiadający własne, ekologiczne centra danych. Potężna i stabilna usługa z dyskiem, mailem i dokumentami.</p>
  </li>
  <li>
    <p><a href="https://mailbox.org/"><strong>Mailbox.org</strong></a> – Ceniony niemiecki dostawca. Zapewniają legendarnie bezpieczną pocztę oraz chmurowy pakiet biurowy (oparty na Open-Xchange).</p>
  </li>
  <li>
    <p><a href="https://proton.me/drive"><strong>Proton Drive</strong></a> – Szwajcarska firma (twórcy ProtonMail), która oferuje usługi z pełnym szyfrowaniem end-to-end (E2EE).</p>
  </li>
</ul>]]></content><author><name>Tomasz Dunia</name></author><category term="przemyslenia" /><category term="szorty" /><category term="office-eu" /><category term="libreoffice" /><category term="openoffice" /><category term="eu" /><category term="europe" /><category term="eufforic" /><category term="maarten-roelfs" /><category term="microsoft-365" /><category term="google-workspace" /><category term="nextcloud" /><category term="saas" /><category term="onlyoffice" /><category term="collabora" /><category term="hetzner" /><category term="infomaniak-kdrive" /><category term="mailbox-org" /><category term="proton-drive" /><summary type="html"><![CDATA[🇵🇱-&gt;🇬🇧 Go to english version of this post / Przejdź do angielskiej wersji tego wpisu]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/officeeu.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/officeeu.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Stremio - an affordable way to enjoy VOD [ENG 🇬🇧]</title><link href="https://blog.tomaszdunia.pl/stremio-eng/" rel="alternate" type="text/html" title="Stremio - an affordable way to enjoy VOD [ENG 🇬🇧]" /><published>2026-03-06T00:00:00+00:00</published><updated>2026-03-06T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/stremio-eng</id><content type="html" xml:base="https://blog.tomaszdunia.pl/stremio-eng/"><![CDATA[<p><a href="https://blog.tomaszdunia.pl/stremio/">🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post</a></p>

<p>Table of contents:</p>
<ul id="markdown-toc">
  <li><a href="#introduction" id="markdown-toc-introduction">Introduction</a></li>
  <li><a href="#what-is-stremio" id="markdown-toc-what-is-stremio">What is Stremio</a></li>
  <li><a href="#differences-from-classic-vod-services" id="markdown-toc-differences-from-classic-vod-services">Differences from Classic VOD Services</a></li>
  <li><a href="#differences-from-kodi-plex-and-jellyfin" id="markdown-toc-differences-from-kodi-plex-and-jellyfin">Differences from Kodi, Plex, and Jellyfin</a></li>
  <li><a href="#basic-configuration" id="markdown-toc-basic-configuration">Basic Configuration</a>    <ul>
      <li><a href="#installation-on-various-devices-tv-computer-phone" id="markdown-toc-installation-on-various-devices-tv-computer-phone">Installation on Various Devices (TV, Computer, Phone)</a></li>
      <li><a href="#stremio-web-browser-version" id="markdown-toc-stremio-web-browser-version">Stremio Web (Browser Version)</a></li>
      <li><a href="#essential-add-ons" id="markdown-toc-essential-add-ons">Essential Add-ons</a></li>
      <li><a href="#real-debrid-or-vpn" id="markdown-toc-real-debrid-or-vpn">Real-Debrid or VPN</a></li>
    </ul>
  </li>
  <li><a href="#stremio-and-legality" id="markdown-toc-stremio-and-legality">Stremio and Legality</a>    <ul>
      <li><a href="#is-using-stremio-legal" id="markdown-toc-is-using-stremio-legal">Is Using Stremio Legal?</a></li>
      <li><a href="#vpn" id="markdown-toc-vpn">VPN</a></li>
      <li><a href="#real-debrid" id="markdown-toc-real-debrid">Real-Debrid</a></li>
      <li><a href="#how-to-get-a-real-debrid-api-key-private-token" id="markdown-toc-how-to-get-a-real-debrid-api-key-private-token">How to Get a Real-Debrid API Key (Private Token)</a></li>
    </ul>
  </li>
  <li><a href="#add-ons" id="markdown-toc-add-ons">Add-ons</a>    <ul>
      <li><a href="#how-add-ons-work" id="markdown-toc-how-add-ons-work">How Add-ons Work</a></li>
      <li><a href="#official-vs-community" id="markdown-toc-official-vs-community">Official vs. Community</a></li>
      <li><a href="#installing-and-configuring-comet" id="markdown-toc-installing-and-configuring-comet">Installing and Configuring Comet</a></li>
      <li><a href="#installing-and-configuring-mediafusion" id="markdown-toc-installing-and-configuring-mediafusion">Installing and Configuring MediaFusion</a></li>
      <li><a href="#installing-and-configuring-torrentio" id="markdown-toc-installing-and-configuring-torrentio">Installing and Configuring Torrentio</a></li>
      <li><a href="#add-ons-on-tv" id="markdown-toc-add-ons-on-tv">Add-ons on TV</a></li>
    </ul>
  </li>
  <li><a href="#basic-usage" id="markdown-toc-basic-usage">Basic Usage</a>    <ul>
      <li><a href="#searching-for-movies-and-series" id="markdown-toc-searching-for-movies-and-series">Searching for Movies and Series</a></li>
      <li><a href="#selecting-a-source-from-the-list" id="markdown-toc-selecting-a-source-from-the-list">Selecting a Source from the List</a></li>
      <li><a href="#subtitles" id="markdown-toc-subtitles">Subtitles</a></li>
      <li><a href="#audio-tracks" id="markdown-toc-audio-tracks">Audio Tracks</a></li>
      <li><a href="#synchronization" id="markdown-toc-synchronization">Synchronization</a></li>
    </ul>
  </li>
  <li><a href="#tracking-what-youve-watched-trakt" id="markdown-toc-tracking-what-youve-watched-trakt">Tracking What You’ve Watched (Trakt)</a></li>
  <li><a href="#savings" id="markdown-toc-savings">Savings</a></li>
  <li><a href="#summary" id="markdown-toc-summary">Summary</a></li>
</ul>

<h2 id="introduction">Introduction</h2>

<p>For me, Stremio is one of the biggest <strong>discoveries of late 2025</strong>. Although I initially approached the subject with skepticism, this platform has completely changed the way we consume media at home. The hardest part of the entire process was convincing my wife to <strong>abandon the familiar and convenient apps</strong>. However, once she saw how it works in practice and that everything is in one place, there could only be one decision: <strong>we cancelled our subscriptions</strong> to all the streaming platforms we had been paying for. The result? My wife now uses Stremio even more often than I do.</p>

<p>If you’re wondering how to free yourself from the rising costs of VOD without sacrificing convenience, this post is for you.</p>

<h2 id="what-is-stremio">What is Stremio</h2>

<p>Stremio is a <strong>free media center application</strong> that serves as a hub for video content. On its own, the program is merely a player with an empty library. It’s only after installing the right extensions (add-ons) that it transforms into a powerful <strong>tool aggregating movies, TV shows, live TV, or podcasts</strong> from various sources into one extremely clean and modern interface.</p>

<h2 id="differences-from-classic-vod-services">Differences from Classic VOD Services</h2>

<p>Classic services (like Netflix, HBO, Disney+, etc.) have their own servers and closed libraries, which require a <strong>monthly subscription</strong> to access. Stremio does not host its own content. It acts as a <strong>search engine and player</strong> – you decide which sources (via add-ons) the app should fetch (or stream on the fly) media from. Instead of jumping between five different apps to find a specific movie, you type the title into Stremio and instantly see all available sources. I guarantee you won’t be able to point me to a piece of content available on any streaming service that I can’t find on Stremio.</p>

<h2 id="differences-from-kodi-plex-and-jellyfin">Differences from Kodi, Plex, and Jellyfin</h2>

<p>This is the most frequent question I received on Mastodon under my posts about Stremio. The differences are fundamental:</p>
<ul>
  <li><strong>Plex / Jellyfin</strong> - This software is for people who already have their own video files on a disk. They require setting up your own server (e.g., on a NAS) that will transcode these files and share them with end devices (TV, tablet, smartphone, or laptop).</li>
  <li><strong>Kodi</strong> - A powerhouse with massive capabilities, but heavy, difficult to configure, and often slow on weaker devices (like cheap TV sticks). Kodi’s add-on configuration is local – if you change devices, you have to set everything up from scratch.</li>
  <li><strong>Stremio</strong> - It’s like Kodi, but lightweight and incredibly simple. Add-ons are installed on your cloud account, not on the device. You install an add-on on your computer, and once you log in on your TV, everything is already there and working. Stremio also doesn’t require keeping files on your own drives – it relies on streaming.</li>
</ul>

<h2 id="basic-configuration">Basic Configuration</h2>

<p>To start watching your first TV show episode through Stremio, you only need a few minutes.</p>

<h3 id="installation-on-various-devices-tv-computer-phone">Installation on Various Devices (TV, Computer, Phone)</h3>

<p>The app is <strong>available on most popular platforms</strong> (Windows, macOS, Linux, Android, Android TV, select Smart TV systems). You can download them here: <strong><a href="https://www.stremio.com/downloads">Official Stremio Website - Downloads</a></strong>.</p>

<h3 id="stremio-web-browser-version">Stremio Web (Browser Version)</h3>

<p>If you don’t want to or can’t install the app on a specific device, you can use the browser version at <a href="https://web.stremio.com/">web.stremio.com</a>.</p>

<h3 id="essential-add-ons">Essential Add-ons</h3>

<p>To get started, you only need three key extensions. They are usually installed by clicking a configuration link on their pages, which redirects you to the Stremio app:</p>
<ul>
  <li><strong><a href="https://comet.elfhosted.com/configure">Comet</a> / <a href="https://mediafusion.elfhosted.com/app">MediaFusion</a></strong> - the main add-ons for finding video sources (torrents). You don’t have to choose just one; installing both provides redundancy (you might also consider <a href="https://torrentio.org/">Torrentio</a>, but its stability has been hit-or-miss lately).</li>
  <li><strong><a href="https://opensubtitles-v3.strem.io/">OpenSubtitles</a></strong> - the official add-on (usually pre-installed), which automatically finds subtitles in your chosen language.</li>
</ul>

<h3 id="real-debrid-or-vpn">Real-Debrid or VPN</h3>

<p>For legal and performance reasons, you need one of the two options below:</p>
<ol>
  <li><strong>VPN</strong> - hides your IP address,</li>
  <li><strong>Real-Debrid</strong> - a service that acts as a proxy; it downloads and shares the file via P2P and then simply streams it to us.</li>
</ol>

<p>I will describe both options in more detail later in this post.</p>

<h2 id="stremio-and-legality">Stremio and Legality</h2>

<blockquote>
  <p><strong>WARNING: Using Stremio in the way I will describe further is balancing on the edge of legality. If this is consistent with your conscience, know that you do so at your own risk. If you are outside of Poland, double-check the regulations regarding the use of P2P networks in your territory.</strong></p>
</blockquote>

<h3 id="is-using-stremio-legal">Is Using Stremio Legal?</h3>

<p>Simply downloading and using Stremio, as well as watching content from official add-ons (e.g., public domain classics), is 100% legal. The issue arises when you install <strong>community add-ons based on torrents</strong>. In this case, Stremio relies on the <strong>BitTorrent protocol (P2P)</strong>. This means that <strong>while watching a movie, you are simultaneously sharing it</strong>, which in many countries carries <strong>heavy financial penalties for copyright infringement</strong>. In Poland, this isn’t as clear-cut, but it can be simplified as: <strong>downloading for personal use is legal, sharing is not</strong>. This seems to be close enough to the truth.</p>

<h3 id="vpn">VPN</h3>

<p>If you have a VPN, it’s fairly easy – a good VPN (if you can trust any of them at all) <strong>should mask your real IP address</strong> and thus protect you from potential legal consequences.</p>

<p>If I were to recommend any (though reluctantly), it would be (order is not accidental):</p>
<ul>
  <li><strong><a href="https://mullvad.net/">Mullvad</a></strong>,</li>
  <li><strong><a href="https://protonvpn.com/">ProtonVPN</a></strong>,</li>
  <li><strong><a href="https://airvpn.org/">AirVPN</a></strong>.</li>
</ul>

<h3 id="real-debrid">Real-Debrid</h3>

<p>This is a much better, cheaper, and often faster solution than a VPN. <strong><a href="https://real-debrid.com/">Real-Debrid</a></strong> is a service that downloads torrents to its own servers and then sends them directly to you via a <strong>secure, encrypted connection (HTTPS)</strong>.</p>
<ul>
  <li>Your IP is never visible in the P2P network (<strong>you aren’t sharing anything</strong>).</li>
  <li>Speed depends only on your connection – no buffering issues, even with 80 GB 4K files.</li>
</ul>

<p>The cost is approximately <strong>$3.50 - $4.50 per month</strong> (depending on the subscription length), and you also collect points that can be exchanged for free premium periods. It is definitely worth it. Of course, it’s not the only solution of this type, but it’s the only one I’ve personally tested and can recommend with a clear conscience.</p>

<h3 id="how-to-get-a-real-debrid-api-key-private-token">How to Get a Real-Debrid API Key (Private Token)</h3>

<p>To connect Stremio to your Real-Debrid account, most add-ons will require a special <strong>API key</strong>. This is your private identifier, which you <strong>should not share with anyone</strong>.</p>

<p>Here are the steps to get it:</p>
<ol>
  <li><strong>Log in</strong> to your account on the <a href="https://real-debrid.com/">Real-Debrid</a> website.</li>
  <li>Ensure you have an <strong>active Premium subscription</strong>.</li>
  <li>Once logged in, <strong>go directly to <a href="https://real-debrid.com/apitoken">this hidden address</a></strong>. The token is also available under the <strong>My Devices</strong> tab.</li>
  <li>On the page, you will see a long string of characters in the <strong>API Private Token</strong> section. <strong>Copy</strong> it – this is your API key that we will use for add-on configuration described later.</li>
</ol>

<h2 id="add-ons">Add-ons</h2>

<p>This is where the power of Stremio lies.</p>

<h3 id="how-add-ons-work">How Add-ons Work</h3>

<p>Add-ons in Stremio are not downloaded to your drive as physical files (unlike Kodi). They run on external web servers. Your Stremio app sends them a query – e.g., <code class="language-plaintext highlighter-rouge">I have movie X, what links and subtitles do you have for it?</code> – and the add-on returns the results. Because of this, the app runs lightning-fast even on the cheapest TVs.</p>

<h3 id="official-vs-community">Official vs. Community</h3>

<ul>
  <li><strong>Official</strong> - Created by the Stremio team (e.g., YouTube, OpenSubtitles, Public Domain Movies). They are fully legal and safe but don’t provide access to the latest cinema hits.</li>
  <li><strong>Community Addons</strong> - Created by independent developers. These integrate Stremio with P2P networks and services like Real-Debrid.</li>
</ul>

<h3 id="installing-and-configuring-comet">Installing and Configuring Comet</h3>

<p>Comet is one of the newest and fastest search add-ons (an alternative to Torrentio) that works great with Real-Debrid and offers high-quality links. It is currently <strong>my number one</strong> choice after having stability issues with Torrentio for several evenings in a row.</p>

<ol>
  <li>Go to the <strong><a href="https://comet.elfhosted.com/configure">Comet configuration page</a></strong>.</li>
  <li>In the <strong>Resolution</strong> field, I recommend selecting:
    <ul>
      <li><strong>4K UHD 2160p</strong>,</li>
      <li><strong>QHD - 1440p</strong>,</li>
      <li><strong>FHD - 1080p</strong>,</li>
      <li><strong>HD - 720p</strong>.</li>
    </ul>
  </li>
  <li>Leave <strong>Max Results Per Resolution</strong> and <strong>Max Size (GB)</strong> at <strong>0</strong>, which means no limit on results or file sizes. If you have a mediocre internet connection and know 4K streaming isn’t possible, consider limiting <em>Max Size</em> to, say, 3 GB.</li>
  <li>Expand the <strong>Debrid Services</strong> section. Click <strong>Add Debrid Service</strong>. Choose <strong>Real-Debrid</strong> from the dropdown. Paste your <strong>API Private Token</strong> into the field on the right.</li>
  <li>Expand the <strong>Language Settings</strong> section. In <strong>Required Languages</strong>, I only have <strong>English</strong> and <strong>Polish</strong> selected, as these are the only two languages I speak fluently and I want Comet to only show content with one of these audio tracks. I also recommend checking <strong>Remove Unknown Languages</strong> to filter out content with missing language metadata. Leave the rest at default.</li>
  <li>In the <strong>Advanced Settings</strong> section, I have <strong>Show Cached Only</strong> and <strong>Remove Trash</strong> checked. The former removes all results that haven’t been cached (pre-loaded) by Real-Debrid. If you find a niche production, you might get a white text on a black background saying it hasn’t been cached yet but will be “available in a moment.” This is the greatest lie in history; it has never happened for me, so I simply filter out anything not already in the buffer.</li>
  <li>Click the buttons at the bottom:
    <ul>
      <li><strong>Install</strong> - opens your device’s Stremio app (or Stremio Web) and installs the configured add-on.</li>
      <li><strong>Copy Link</strong> - copies a long configuration URL to your clipboard. To use this manually, go to Stremio -&gt; Add-ons -&gt; Add Add-on and paste the link.</li>
      <li><strong>Setup Kodi</strong> - not applicable here.</li>
    </ul>
  </li>
</ol>

<h3 id="installing-and-configuring-mediafusion">Installing and Configuring MediaFusion</h3>

<p>MediaFusion is a powerful “Swiss Army knife” that provides movies, series, sports events, and live TV. It has advanced scraping options, including regional trackers. <strong>It’s my number two</strong> – a backup for when Comet fails, which has happened maybe once. Configuration is similar to Comet, just with options in different places.</p>

<ol>
  <li>Go to the <strong><a href="https://mediafusion.elfhosted.com/configure">MediaFusion configuration page</a></strong>.</li>
  <li>Unlike Comet, everything here is organized into tabs. Start with <strong>Provider</strong>. Click <strong>Add Streaming Provider</strong>, choose Real-Debrid, and enter any <strong>Provider Name</strong>. You can either authorize via the <strong>Authorize Real-Debrid</strong> button or paste your <strong>API Private Token</strong>. Enable <strong>Only Show Cached Streams</strong>.</li>
  <li>Go to the <strong>Preferences</strong> tab. In <strong>Resolutions</strong>, leave: <strong>4K</strong>, <strong>2160p</strong>, <strong>1440p</strong>, <strong>1080p</strong>, and <strong>720p</strong>. In <strong>Quality Filter</strong>, choose: <strong>BluRay/UHD</strong>, <strong>WEB/HD</strong>, and <strong>DVD/TV/SAT</strong>. In <strong>File Size Filters</strong>, you can set limits or leave them empty. In <strong>Preferred Languages</strong>, I set <strong>English</strong> and <strong>Polish</strong>.</li>
  <li>Leave other tabs at default or explore them later.</li>
  <li>Click the purple <strong>Generate Install URL</strong> button. A window with a long link will appear. Paste it into Stremio as you did with Comet.</li>
</ol>

<h3 id="installing-and-configuring-torrentio">Installing and Configuring Torrentio</h3>

<p>Torrentio is the classic and likely the most popular add-on of its kind, but its popularity may have hurt it; servers have struggled with the influx of new Stremio users. I hope it stabilizes soon, but it is currently <strong>my number three</strong> – the backup of the backup.</p>

<ol>
  <li>Open the <strong><a href="https://torrentio.strem.fun/configure">Torrentio configuration page</a></strong>.</li>
  <li>In <strong>Providers</strong>, leave defaults.</li>
  <li>In <strong>Sorting</strong>, I recommend <strong>By quality then seeders</strong>.</li>
  <li>Leave <strong>Max Results per Quality</strong> blank (<strong>All results</strong>).</li>
  <li>In <strong>Priority Language</strong>, I selected <strong>Polish</strong> (English is usually default).</li>
  <li>In <strong>Exclude Resolutions</strong>, check: <strong>Unknown</strong>, <strong>Cam</strong>, <strong>Screener</strong>, and <strong>480p</strong>.</li>
  <li>Leave <strong>Video Size Limit</strong> blank if your internet can handle it.</li>
  <li>Most importantly, in <strong>Debrid Provider</strong>, select <strong>RealDebrid</strong> and paste your <strong>API Private Token</strong>.</li>
  <li>Click <strong>Install</strong> or <strong>Copy Link</strong> at the bottom.</li>
</ol>

<h3 id="add-ons-on-tv">Add-ons on TV</h3>

<p>In the original version of this post, I forgot to mention this, so I am now editing it to say that <strong>add-ons cannot be edited from the TV app</strong>. After entering the Add-ons tab on the TV, you will only see a large button to synchronize the add-ons that you have previously installed and configured from your browser or application on your laptop or phone/tablet.</p>

<h2 id="basic-usage">Basic Usage</h2>

<h3 id="searching-for-movies-and-series">Searching for Movies and Series</h3>

<p>Simply use the <strong>search bar</strong> or browse the home screen (<strong>Discover</strong> or <strong>Board</strong>). If you’ve installed <strong>catalog add-ons</strong>, it will look like Netflix or similar platforms. For catalogs, the default <strong><a href="https://v3-cinemeta.strem.io/">Cinemeta</a></strong> is sufficient for me.</p>

<h3 id="selecting-a-source-from-the-list">Selecting a Source from the List</h3>

<p>After choosing an episode, a list of options will appear. These are scraped from <strong>all your sources</strong> (Comet, MediaFusion, Torrentio). They are <strong>sorted</strong> by add-on, then resolution, seeders, or size. <strong>Don’t overthink it</strong>. <strong>Just click</strong> the first one. If something is wrong (doesn’t work, poor quality, bad audio, wrong language, no subtitles), just pick the next one on the list.</p>

<p><img src="/images/stremio1.png" alt="Screenshot from Stremio - list of series" /></p>

<p><img src="/images/stremio2.png" alt="Screenshot from Stremio - list of episodes of Picard series" /></p>

<h3 id="subtitles">Subtitles</h3>

<p>Stremio <strong>automatically tries to fetch subtitles</strong> from the OpenSubtitles add-on based on your account language settings. During playback, you can click the subtitle icon to <strong>change source, language, or fix synchronization</strong> (delay) on the fly. Pro tip: sync issues often happen because subtitles were made for a version without a “Previously on…” recap. Simply <strong>delay</strong> the subtitles by the length of that fragment. I also recommend checking <strong>Stremio settings</strong> to set a <strong>preferred subtitle language</strong> and a transparent background for easier reading.</p>

<h3 id="audio-tracks">Audio Tracks</h3>

<p>If a file has multiple audio tracks (e.g., Original and Polish Dub/Lector), you’ll find an <strong>audio icon</strong> next to the subtitle icon, allowing you to <strong>seamlessly switch between available languages</strong>.</p>

<h3 id="synchronization">Synchronization</h3>

<p>Stremio <strong>syncs information across all devices</strong> connected to the same account. This isn’t just about your library or “Watched” status – you can start watching a movie on your phone, move to your computer, and the <strong>player will automatically start exactly where you left off</strong>. It’s impressive because you can even switch sources (e.g., Comet on the phone, MediaFusion on the PC), and Stremio still handles it. Since <strong>Stremio is open-source</strong>, I might dig into the code one day to see how this works under the hood.</p>

<h2 id="tracking-what-youve-watched-trakt">Tracking What You’ve Watched (Trakt)</h2>

<p>For those who love full statistics, Stremio offers <strong>integration with <a href="https://trakt.tv/">Trakt.tv</a></strong>. Once paired, the app <strong>automatically checks off watched episodes</strong>. Personally, I don’t use it because I’ve used <strong>TV Time</strong> for ages (which doesn’t sync with Stremio), but <strong>many people swear by Trakt</strong>, so it’s worth mentioning.</p>

<h2 id="savings">Savings</h2>

<p>I believe I’ve shown that <strong>Stremio isn’t just about saving money – it’s about convenience and independence</strong>. However, for the sake of completeness, let’s look at exactly how much you can save.</p>

<p>I checked the offers of all popular streaming platforms (converted to USD):</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">VOD Service</th>
      <th style="text-align: left">Cheapest Plan</th>
      <th style="text-align: left">Most Expensive Plan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong><em>Netflix</em></strong></td>
      <td style="text-align: left">$8.35</td>
      <td style="text-align: left">$16.96</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>Max (HBO)</em></strong></td>
      <td style="text-align: left">$6.31</td>
      <td style="text-align: left">$10.53</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>Disney+</em></strong></td>
      <td style="text-align: left">$7.38</td>
      <td style="text-align: left">$12.66</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>SkyShowtime</em></strong></td>
      <td style="text-align: left">$4.22</td>
      <td style="text-align: left">$8.42</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>Apple TV+</em></strong></td>
      <td style="text-align: left">$8.86</td>
      <td style="text-align: left">$8.86</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>Amazon Prime</em></strong></td>
      <td style="text-align: left">$1.46</td>
      <td style="text-align: left">$1.46</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>TOTAL</strong></td>
      <td style="text-align: left"><strong>$36.58 / mo</strong></td>
      <td style="text-align: left"><strong>$58.89 / mo</strong></td>
    </tr>
  </tbody>
</table>

<p><em>Note: Prices current as of March 6, 2026. Monthly costs for cheapest plans often reflect annual billing discounts (~16% savings). Prices for Polish market.</em></p>

<p>As you can see, you save a <strong>minimum of $36.58 per month</strong>, but that’s for the worst quality plans (often <strong>720p or with ads</strong>). <strong>Stremio should be compared to the $58.89 amount</strong> because that’s the quality it offers – everything maxed out. The real cost of Stremio is only the Real-Debrid subscription, which is about <strong>$4.30</strong>.</p>

<p>Not to mention, <strong>Stremio features productions that cannot be found on any of these six leading platforms</strong>. A prime example is <strong>Schitt’s Creek</strong>, which my wife hunted for a long time; it is not available on any streaming subscription in Poland. This is certainly not the only such case.</p>

<h2 id="summary">Summary</h2>
<p>Stremio combined with Real-Debrid is a solution that, once configured, just works. It’s no longer a hobby for enthusiasts but a <strong>fully-fledged, stable alternative to the fragmented VOD market</strong>. If you are intimidated by <strong>rising subscription prices</strong> and the fact that your favorite <strong>series are scattered</strong> across five different apps – give Stremio a chance. Your wife (and your wallet) will likely thank you. I speak from experience.</p>

<p>Questions about configuration? Feel free to reach out on <a href="https://infosec.exchange/@to3k">Mastodon</a> or in the comments section below!</p>]]></content><author><name>Tomasz Dunia</name></author><category term="movies-and-series" /><category term="thoughts" /><category term="tutorials" /><category term="stremio" /><category term="read-debrid" /><category term="comet" /><category term="mediafusion" /><category term="torrentio" /><category term="netflix" /><category term="hbo" /><category term="disney" /><category term="skyshowtime" /><category term="apple-tv" /><category term="amazon-prime" /><category term="streaming" /><category term="tv" /><category term="series" /><category term="movies" /><summary type="html"><![CDATA[🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/stremio.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/stremio.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Stremio – tani sposób na VOD</title><link href="https://blog.tomaszdunia.pl/stremio/" rel="alternate" type="text/html" title="Stremio – tani sposób na VOD" /><published>2026-03-06T00:00:00+00:00</published><updated>2026-03-06T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/stremio</id><content type="html" xml:base="https://blog.tomaszdunia.pl/stremio/"><![CDATA[<p><a href="https://blog.tomaszdunia.pl/stremio-eng/">🇵🇱-&gt;🇬🇧 Go to english version of this post / Przejdź do angielskiej wersji tego wpisu</a></p>

<p>Spis treści:</p>
<ul id="markdown-toc">
  <li><a href="#wstęp" id="markdown-toc-wstęp">Wstęp</a></li>
  <li><a href="#czym-jest-stremio" id="markdown-toc-czym-jest-stremio">Czym jest Stremio</a></li>
  <li><a href="#różnice-względem-klasycznych-serwisów-vod" id="markdown-toc-różnice-względem-klasycznych-serwisów-vod">Różnice względem klasycznych serwisów VOD</a></li>
  <li><a href="#różnice-względem-kodi-plex-i-jellyfin" id="markdown-toc-różnice-względem-kodi-plex-i-jellyfin">Różnice względem Kodi, Plex i Jellyfin</a></li>
  <li><a href="#podstawowa-konfiguracja" id="markdown-toc-podstawowa-konfiguracja">Podstawowa konfiguracja</a>    <ul>
      <li><a href="#instalacja-na-różnych-urządzeniach-tv-komputer-telefon" id="markdown-toc-instalacja-na-różnych-urządzeniach-tv-komputer-telefon">Instalacja na różnych urządzeniach (TV, komputer, telefon)</a></li>
      <li><a href="#wersja-przeglądarkowa-stremio-web" id="markdown-toc-wersja-przeglądarkowa-stremio-web">Wersja przeglądarkowa Stremio Web</a></li>
      <li><a href="#niezbędne-dodatki" id="markdown-toc-niezbędne-dodatki">Niezbędne dodatki</a></li>
      <li><a href="#real-debrid-albo-vpn" id="markdown-toc-real-debrid-albo-vpn">Real-Debrid albo VPN</a></li>
    </ul>
  </li>
  <li><a href="#stremio-a-legalność" id="markdown-toc-stremio-a-legalność">Stremio a legalność</a>    <ul>
      <li><a href="#czy-używanie-stremio-jest-legalne" id="markdown-toc-czy-używanie-stremio-jest-legalne">Czy używanie Stremio jest legalne?</a></li>
      <li><a href="#vpn" id="markdown-toc-vpn">VPN</a></li>
      <li><a href="#real-debrid" id="markdown-toc-real-debrid">Real-Debrid</a></li>
      <li><a href="#jak-pozyskać-klucz-real-debrid-api-token" id="markdown-toc-jak-pozyskać-klucz-real-debrid-api-token">Jak pozyskać klucz Real-Debrid (API Token)</a></li>
    </ul>
  </li>
  <li><a href="#dodatki" id="markdown-toc-dodatki">Dodatki</a>    <ul>
      <li><a href="#jak-działają-dodatki" id="markdown-toc-jak-działają-dodatki">Jak działają dodatki</a></li>
      <li><a href="#oficjalne-vs-społecznościowe" id="markdown-toc-oficjalne-vs-społecznościowe">Oficjalne vs społecznościowe</a></li>
      <li><a href="#instalacja-i-konfiguracja-comet" id="markdown-toc-instalacja-i-konfiguracja-comet">Instalacja i konfiguracja Comet</a></li>
      <li><a href="#instalacja-i-konfiguracja-mediafusion" id="markdown-toc-instalacja-i-konfiguracja-mediafusion">Instalacja i konfiguracja MediaFusion</a></li>
      <li><a href="#instalacja-i-konfiguracja-torrentio" id="markdown-toc-instalacja-i-konfiguracja-torrentio">Instalacja i konfiguracja Torrentio</a></li>
      <li><a href="#dodatki-na-tv" id="markdown-toc-dodatki-na-tv">Dodatki na TV</a></li>
    </ul>
  </li>
  <li><a href="#podstawowa-obsługa" id="markdown-toc-podstawowa-obsługa">Podstawowa obsługa</a>    <ul>
      <li><a href="#wyszukiwanie-seriali-i-filmów" id="markdown-toc-wyszukiwanie-seriali-i-filmów">Wyszukiwanie seriali i filmów</a></li>
      <li><a href="#wybór-odpowiedniego-źródła--pliku-źródłowego-z-listy" id="markdown-toc-wybór-odpowiedniego-źródła--pliku-źródłowego-z-listy">Wybór odpowiedniego źródła / pliku źródłowego z listy</a></li>
      <li><a href="#napisy" id="markdown-toc-napisy">Napisy</a></li>
      <li><a href="#ścieżki-dźwiękowe" id="markdown-toc-ścieżki-dźwiękowe">Ścieżki dźwiękowe</a></li>
      <li><a href="#synchronizacja" id="markdown-toc-synchronizacja">Synchronizacja</a></li>
    </ul>
  </li>
  <li><a href="#śledzenie-tego-co-się-obejrzało-trakt" id="markdown-toc-śledzenie-tego-co-się-obejrzało-trakt">Śledzenie tego co się obejrzało (Trakt)</a></li>
  <li><a href="#oszczędności" id="markdown-toc-oszczędności">Oszczędności</a></li>
  <li><a href="#podsumowanie" id="markdown-toc-podsumowanie">Podsumowanie</a></li>
</ul>

<h2 id="wstęp">Wstęp</h2>

<p>Stremio to dla mnie jedno z największych <strong>odkryć końcówki 2025 roku</strong>. Choć początkowo podchodziłem do tematu sceptycznie, platforma ta całkowicie zmieniła sposób, w jaki konsumujemy media w domu. Najtrudniejszą częścią całego procesu było przekonanie żony do <strong>porzucenia znanych i wygodnych aplikacji</strong>. Gdy jednak zobaczyła, jak to działa w praktyce i że wszystko mamy w jednym miejscu, decyzja mogła być tylko jedna: <strong>zrezygnowaliśmy z subskrypcji</strong> wszystkich platform streamingowych, które do tej pory opłacaliśmy. Finał jest taki, że teraz to moja żona częściej korzysta ze Stremio niż ja.</p>

<p>Jeśli zastanawiasz się, jak uwolnić się od rosnących kosztów VOD bez utraty wygody, to właśnie o tym będzie ten wpis.</p>

<h2 id="czym-jest-stremio">Czym jest Stremio</h2>

<p>Stremio to <strong>darmowa aplikacja</strong> typu media center (z ang. centrum multimedialne), która służy jako hub dla treści wideo. Sam w sobie program jest jedynie odtwarzaczem z pustą biblioteką. Dopiero po zainstalowaniu odpowiednich rozszerzeń (dodatków) zamienia się w potężne <strong>narzędzie agregujące filmy, seriale, telewizję na żywo czy podcasty</strong> z różnych źródeł w jednym, niezwykle czytelnym i nowoczesnym interfejsie.</p>

<h2 id="różnice-względem-klasycznych-serwisów-vod">Różnice względem klasycznych serwisów VOD</h2>

<p>Klasyczne serwisy (jak Netflix, HBO, Disney+ itd.) posiadają własne serwery i zamknięte biblioteki, do których dostęp wymaga opłacania <strong>miesięcznego abonamentu</strong>. Stremio nie posiada własnych treści. Działa jak <strong>wyszukiwarka i odtwarzacz</strong> – Ty decydujesz, z jakich źródeł (dzięki dodatkom) aplikacja ma pobierać (lub streamować - odtwarzać w locie) media. Zamiast skakać po pięciu różnych aplikacjach w poszukiwaniu konkretnego filmu, wpisujesz tytuł w Stremio i od razu widzisz dostępne źródła. Gwarantuję Ci, że nie uda Ci się wskazać mi jakiegoś materiału, który jest dostępny na dowolnym serwisie streamingowym, a nie znajdę go na Stremio.</p>

<h2 id="różnice-względem-kodi-plex-i-jellyfin">Różnice względem Kodi, Plex i Jellyfin</h2>

<p>To najczęstsze pytanie, jakie otrzymywałem na Mastodonie pod postami o Stremio. Różnice są fundamentalne:</p>
<ul>
  <li><strong>Plex / Jellyfin</strong> - To oprogramowanie dla osób, które już posiadają własne pliki wideo na dysku. Wymagają postawienia własnego serwera (np. na NAS), który będzie te pliki transkodował i udostępniał urządzeniom końcowym (telewizor, tablet, smartfon czy laptop).</li>
  <li><strong>Kodi</strong> - To kombajn o ogromnych możliwościach, ale ciężki, trudny w konfiguracji i często wolny na słabszych urządzeniach (np. tanich przystawkach TV). Konfiguracja dodatków w Kodi jest lokalna – jeśli zmienisz urządzenie, musisz ustawiać wszystko od nowa.</li>
  <li><strong>Stremio</strong> - To takie Kodi, ale lekkie i banalnie proste. Dodatki instaluje się na koncie w chmurze, a nie na urządzeniu. Instalujesz dodatek na komputerze, a po zalogowaniu na telewizorze wszystko już tam jest i działa. Stremio nie wymaga też trzymania plików na własnych dyskach – opiera się na streamingu.</li>
</ul>

<h2 id="podstawowa-konfiguracja">Podstawowa konfiguracja</h2>

<p>Aby rozpocząć oglądanie swojego pierwszego odcinka serialu przez Stremio, wystarczy kilka minut.</p>

<h3 id="instalacja-na-różnych-urządzeniach-tv-komputer-telefon">Instalacja na różnych urządzeniach (TV, komputer, telefon)</h3>

<p>Aplikacja jest <strong>dostępna na większość popularnych platform</strong> (Windows, macOS, Linux, Android, Android TV, wybrane systemy Smart TV). Pobierzesz je stąd: <strong><a href="https://www.stremio.com/downloads">Oficjalna strona Stremio - Pobieranie</a></strong>.</p>

<h3 id="wersja-przeglądarkowa-stremio-web">Wersja przeglądarkowa Stremio Web</h3>

<p>Jeśli nie chcesz lub nie możesz zainstalować aplikacji na danym urządzeniu, możesz skorzystać z wersji w przeglądarce pod adresem <a href="https://web.stremio.com/">web.stremio.com</a>.</p>

<h3 id="niezbędne-dodatki">Niezbędne dodatki</h3>

<p>Na start wystarczą Ci trzy kluczowe rozszerzenia. Instaluje się je zazwyczaj poprzez kliknięcie linku konfiguracyjnego na ich stronach i przekierowanie do aplikacji Stremio:</p>
<ul>
  <li><strong><a href="https://comet.elfhosted.com/configure">Comet</a> / <a href="https://mediafusion.elfhosted.com/app">MediaFusion</a></strong> - główne dodatki wyszukujące źródła wideo (torrenty), nie trzeba się decydować na jeden, bo instalacja dwóch zapewnia redundancję (można jeszcze rozważyć <a href="https://torrentio.org/">Torrentio</a>, ale ostatnio kiepsko ze stabilnością tego dodatku).</li>
  <li><strong><a href="https://opensubtitles-v3.strem.io/">OpenSubtitles</a></strong> - oficjalny dodatek (zazwyczaj zainstalowany domyślnie), który automatycznie dobiera napisy w wybranym języku.</li>
</ul>

<h3 id="real-debrid-albo-vpn">Real-Debrid albo VPN</h3>

<p>Ze względów prawnych potrzebujesz jednej z dwóch poniższych opcji:</p>
<ol>
  <li><strong>VPN</strong> - ukryje Twój adres IP,</li>
  <li><strong>Real-Debrid</strong> - usługa, która robi za pośrednika, tj. pobiera i udostępnia plik w ramach P2P, a nam tylko go streamuje.</li>
</ol>

<p>Obie z tych opcji opiszę dokładniej w dalszej części wpisu.</p>

<h2 id="stremio-a-legalność">Stremio a legalność</h2>

<blockquote>
  <p><strong>UWAGA: Korzystanie ze Stremio w sposób, który opiszę w dalszej części tego wpisu jest balansowaniem na granicy legalności. Jeżeli jest to zgodne z Twoim sumieniem to wiedz, że robisz to na własną odpowiedzialność. Jeżeli nie przebywasz na terenie Polski to dwa razy sprawdź jak wyglądają przepisy w zakresie korzystania z sieci P2P na danym terytorium.</strong></p>
</blockquote>

<h3 id="czy-używanie-stremio-jest-legalne">Czy używanie Stremio jest legalne?</h3>

<p>Samo pobranie i używanie Stremio, jak i oglądanie treści z oficjalnych dodatków (np. klasyki w domenie publicznej), jest w 100% legalne. Problem pojawia się w momencie instalacji <strong>dodatków społecznościowych opartych na torrentach</strong>. W takim przypadku Stremio opiera się na <strong>protokole BitTorrent (P2P)</strong>. Oznacza to, że <strong>oglądając film, jednocześnie go udostępniasz</strong>, co w wielu krajach wiąże się z <strong>surowymi karami finansowymi za naruszenie praw autorskich</strong>. W Polsce nie jest to taki oczywisty temat, ale maksymalnie można go uprościć do - <strong>pobieranie do użytku własnego jest legalne, udostępnianie już nie</strong>. Wydaje mi się, że nie mija się to z prawdą.</p>

<h3 id="vpn">VPN</h3>

<p>W przypadku posiadania VPN sprawa jest o tyle łatwa, że dobry VPN (o ile w ogóle można zaufać któremukolwiek z nich) <strong>powinien zamaskować nasz realny adres IP</strong> i w ten sposób uchronić nas od ewentualnych konsekwencji prawnych.</p>

<p>Jeżeli miałbym coś polecić (choć niechętnie) to byłyby to (kolejność nie jest przypadkowa):</p>
<ul>
  <li><strong><a href="https://mullvad.net/pl">Mullvad</a></strong>,</li>
  <li><strong><a href="https://protonvpn.com/">ProtonVPN</a></strong>,</li>
  <li><strong><a href="https://airvpn.org/">AirVPN</a></strong>.</li>
</ul>

<h3 id="real-debrid">Real-Debrid</h3>

<p>To znacznie lepsze, tańsze i niejednokrotnie szybsze rozwiązanie niż VPN. <strong><a href="https://real-debrid.com/">Real-Debrid</a></strong> to usługa, która pobiera torrenty na swoje serwery, a następnie przesyła je do Ciebie bezpośrednio, <strong>bezpiecznym, szyfrowanym połączeniem (HTTPS)</strong>.</p>
<ul>
  <li>Twoje IP nigdzie nie jest widoczne w sieci P2P (<strong>nic nie udostępniasz</strong>).</li>
  <li>Szybkość zależy tylko od Twojego łącza – brak problemów z buforowaniem, nawet przy plikach 4K o wadze 80 GB.</li>
</ul>

<p>Koszt to około <strong>3-4 euro miesięcznie</strong> (w zależności od długości zobowiązania), a do tego zbiera się jeszcze punkty, które co jakiś czas można wymienić na darmowy okres premium. Zdecydowanie warto. Oczywiście nie jest to jedyne rozwiązanie tego typu, ale tylko to osobiście przetestowałem i mogę polecić z czystym sumieniem.</p>

<h3 id="jak-pozyskać-klucz-real-debrid-api-token">Jak pozyskać klucz Real-Debrid (API Token)</h3>

<p>Aby połączyć Stremio z kontem Real-Debrid, większość dodatków będzie wymagała podania specjalnego <strong>klucza API</strong>. Jest to Twój prywatny identyfikator, którego <strong>nie powinieneś nikomu udostępniać</strong>.</p>

<p>Oto kroki jak go zdobyć:</p>
<ol>
  <li><strong>Zaloguj się</strong> na swoje konto na stronie <a href="https://real-debrid.com/">Real-Debrid</a>.</li>
  <li>Upewnij się, że masz <strong>wykupioną subskrypcję</strong> Premium na platformie Real-Debrid.</li>
  <li>Po zalogowaniu <strong>przejdź bezpośrednio pod <a href="https://real-debrid.com/apitoken">ten ukryty adres</a></strong>. Token jest też dostępny w zakładce <strong>My Devices</strong>.</li>
  <li>Na stronie zobaczysz długi ciąg znaków w sekcji <strong>API Private Token</strong>. <strong>Skopiuj</strong> go – to właśnie Twój klucz API, który przyda nam się podczas konfiguracji dodatków opisanej w dalszej części wpisu.</li>
</ol>

<h2 id="dodatki">Dodatki</h2>

<p>To właśnie one stanowią o sile Stremio.</p>

<h3 id="jak-działają-dodatki">Jak działają dodatki</h3>

<p>Dodatki w Stremio nie są pobierane na Twój dysk jako fizyczne pliki (jak w Kodi). Działają po stronie zewnętrznych serwerów internetowych. Twoja aplikacja Stremio wysyła do nich zapytanie - np. <code class="language-plaintext highlighter-rouge">Mam film X, jakie masz do niego linki i napisy?</code>, a dodatek zwraca gotowe wyniki. Dzięki temu aplikacja działa błyskawicznie nawet na najtańszych telewizorach.</p>

<h3 id="oficjalne-vs-społecznościowe">Oficjalne vs społecznościowe</h3>

<ul>
  <li><strong>Oficjalne</strong> - Tworzone przez twórców Stremio (np. YouTube, OpenSubtitles, Public Domain Movies). Są w pełni legalne i bezpieczne, ale nie dają dostępu do najnowszych kinowych hitów.</li>
  <li><strong>Społecznościowe (Community Addons)</strong> - Tworzone przez niezależnych deweloperów. To one integrują Stremio z sieciami P2P i serwisami typu Real-Debrid.</li>
</ul>

<h3 id="instalacja-i-konfiguracja-comet">Instalacja i konfiguracja Comet</h3>

<p>Comet to jeden z najnowszych i najszybszych dodatków wyszukujących (alternatywa dla Torrentio), który świetnie współpracuje z Real-Debrid i oferuje bardzo wysoką jakość linków. To obecnie <strong>mój numer jeden</strong> po tym jak kilka wieczorów z rzędu miałem problemy z Torrentio.</p>

<ol>
  <li>Wejdź na <strong><a href="https://comet.elfhosted.com/configure">stronę konfiguracyjną dodatku Comet</a></strong>.</li>
  <li>W polu <strong>Resolution</strong> proponuję wybrać:
    <ul>
      <li><strong>4K UHD 2160p</strong>,</li>
      <li><strong>QHD - 1440p</strong>,</li>
      <li><strong>FHD - 1080p</strong>,</li>
      <li><strong>HD - 720p</strong>.</li>
    </ul>
  </li>
  <li>W <strong>Max Results Per Resolution</strong> i <strong>Max Size (GB)</strong> zostawmy <strong>0</strong>, co oznacza, że nie chcemy limitu ilości wyników oraz rozmiaru plików. Jeżeli masz średnie połączenie internetowe i wiesz, że streaming filmu 4K nie będzie możliwy to możesz rozważyć ograniczenie parametru <em>Max Size</em> do np. 3 GB.</li>
  <li>Rozwijamy sekcję <strong>Debrid Services</strong>. Naciskamy przycisk <strong>Add Debrid Service</strong>. Z listy rozwijanej wybieramy <strong>Real-Debrid</strong> (lub innego dostawcę który został wybrany). W pole po prawej wklejamy <strong>API Private Token</strong>, który pozyskaliśmy w poprzednim rozdziale tego wpisu.</li>
  <li>Rozwińmy sekcję <strong>Language Settings</strong>. W polu <strong>Required Languages</strong> mam wybrane tylko <strong>English</strong> i <strong>Polish</strong>, bo są to jedyne dwa języki, którymi posługuję się biegle i chcę, żeby Comet pokazywał mi tylko seriale/filmy, które posiadają jedną z tych dwóch ścieżek dźwiękowych. Polecam jeszcze zaznaczyć opcję <strong>Remove Unknown Languages</strong>, co odfiltruje materiały, w których metadanych nie określono dostępnych języków. Resztę zostawiam bez zmian względem domyślnego ustawienia.</li>
  <li>W ostatniej sekcji <strong>Advanced Settings</strong> mam zaznaczone opcje <strong>Show Cached Only</strong> i <strong>Remove Trash</strong>. To pierwsze usuwa z wyników wyszukiwania wszystkie propozycje, które nie zostały jeszcze zacachowane (z ang. załadowane do bufora) przez Real-Debrid. Chodzi o to, że jak znajdziemy wystarczająco niszową produkcję to zamiast odcinka serialu otrzymamy wielki biały napis na czarnym tle mówiący o tym, że ten materiał nie został jeszcze zacachowany przez Real-Debrid, ale jak poczekamy chwilę to za moment będzie on dostępny. Jest to największe kłamstwo w historii kłamstw, bo jeszcze nigdy w moim przypadku tak się nie stało, dlatego po prostu wywalam te materiały, których nie ma w buforze Real-Debrid.</li>
  <li>Doszliśmy do końca konfiguratora i widzimy na samym dole trzy przyciski:
    <ul>
      <li><strong>Install</strong> - przeniesie nas bezpośrednio do aplikacji Stremio odpowiedniej dla naszego urządzenia lub jeżeli takiej nie mamy to otworzy Stremio Web i w ten sposób zainstaluje nam dodatek skonfigurowany zgodnie z tym co wyklikaliśmy powyżej,</li>
      <li><strong>Copy Link</strong> - jego naciśnięcie spowoduje skopiowanie do schowka odpowiedniego, długiego linku, który zawiera wszystkie informacje na temat naszej konfiguracji, aby użyć tego linku należy przejść ręcznie do Stremio, zakładka Dodatki, nacisnąć Dodaj dodatek i wkleić ten link w pole do podawania adresu dodatku,</li>
      <li><strong>Setup Kodi</strong> - ten przycisk nie ma zastosowania w naszym przypadku.</li>
    </ul>
  </li>
</ol>

<h3 id="instalacja-i-konfiguracja-mediafusion">Instalacja i konfiguracja MediaFusion</h3>

<p>MediaFusion to potężny kombajn, który potrafi dostarczyć filmy, seriale, a także wydarzenia sportowe i telewizję na żywo. Posiada zaawansowane opcje scrapowania, w tym treści z regionalnych trackerów. <strong>Dla mnie to numer dwa</strong>, czyli rezerwa na wypadek potknięcia Comet, co przez cały czas zdarzyło mi się może jeden raz. Konfiguracja jest bardzo podobna do Comet tylko poszczególne opcje są w innych miejscach.</p>

<ol>
  <li>Przejdź na <strong><a href="https://mediafusion.elfhosted.com/configure">stronę konfiguratora MediaFusion</a></strong>.</li>
  <li>W przeciwieństwie do Comet tutaj wszystko jest poukładane w zakładkach. Pierwszą, którą odwiedzamy jest <strong>Provider</strong>. Naciskamy przycisk <strong>Add Streaming Provider</strong>, z listy rozwijanej wybieramy Real-Debrid (lub inny wedle uznania), wpisujemy dowolny <strong>Provider Name</strong>. Teraz mamy dwie opcje - autoryzujemy się poprzez przycisk <strong>Authorize Real-Debrid</strong> i wykonanie krótkiej instrukcji, albo po prostu podajemy <strong>API Private Token</strong> w polu poniżej. Na koniec na dole mamy opcję <strong>Only Show Cached Streams</strong>, czyli tak jak w przypadku Comet włączamy opcję wyświetlania tylko zacachowanych materiałów przez Real-Debrid.</li>
  <li>Następna zakładka, która nas interesuje to <strong>Preferences</strong>. W sekcji <strong>Resolutions</strong> polecam zostawić tylko: <strong>4K</strong>, <strong>2160p</strong>, <strong>1440p</strong>, <strong>1080p</strong> i <strong>720p</strong>. W <strong>Quality Filter</strong> polecam: <strong>BluRay/UHD</strong>, <strong>WEB/HD</strong> i <strong>DVD/TV/SAT</strong>. W <strong>File Size Filters</strong> możemy ustawić minimalną i maksymalną wielkość pliku (można też zostawić bez limitu) oraz ile ma być wyników na daną rozdzielczość i tutaj nie można podać 0, więc jeżeli nie chcesz mieć limitu to podaj jakąś wysoką liczbę. W <strong>Preferred Languages</strong> ustawiłem <strong>English</strong> i <strong>Polish</strong>. Reszta opcji w tej zakładce jest dla mnie nieistotna.</li>
  <li>Pozostałe zakładki proponuję zostawić w domyślnej formie lub ewentualnie później w wolnej chwili zajrzeć do nich i może coś podkręcić.</li>
  <li>Po dojściu do tego momentu szukamy fioletowego przycisku <strong>Generate Install URL</strong>, który znajduje się zarówno na górze jak i na dole konfiguratora. W rezultacie jego naciśnięcia pojawi nam się okienko z wygenerowanym długim linkiem z zakodowanymi wszystkimi naszymi ustawieniami. Wklejamy go w naszym Stremio tak samo jak w przypadku Comet.</li>
</ol>

<h3 id="instalacja-i-konfiguracja-torrentio">Instalacja i konfiguracja Torrentio</h3>

<p>Torrentio to klasyk i chyba najpopularniejszy dodatek tego typu do Stremio, ale wydaje mi się, że jego popularność i przede wszystkim wystrzał popularności Stremio trochę mu zaszkodziły i jego serwery po prostu nie wytrzymały naporu. Liczę na to, że sytuacja się niedługo unormuje, ale póki co mam z tym dodatkiem najgorsze doświadczenia, więc jest <strong>dopiero moim numerem trzy</strong> jako rezerwa rezerwy.</p>

<ol>
  <li>Otwórz <strong><a href="https://torrentio.strem.fun/configure">stronę konfiguratora Torrentio</a></strong>.</li>
  <li>W sekcji <strong>Providers</strong> nie musisz nic zmieniać – domyślnie wyszukuje w najważniejszych miejscach.</li>
  <li>Z listy rozwijanej <strong>Sorting</strong> polecam wybrać <strong>By quality then seeders</strong>, co posortuje nam wyniki najpierw pod względem jakości, a później tego ilu użytkowników sieci P2P deklaruje możliwość udostępnienia tego materiału.</li>
  <li>W polu <strong>Max Results per Quality</strong> nie podajemy żadnej liczby, czyli zostawiamy <strong>All results</strong>. tj. nie limitujemy ilości wyników.</li>
  <li>Na liście <strong>Priority Language</strong> zaznaczyłem tylko <strong>Polish</strong>. O dziwo nie ma tu angielskiego, ale zakładam, że jest wybierany domyślnie.</li>
  <li>W sekcji <strong>Exclude Resolutions</strong> poprzez zaznaczenie wykluczamy dane rozdzielczości, więc zaznaczamy: <strong>Unknown</strong>, <strong>Cam</strong>, <strong>Screener</strong> i <strong>480p</strong>.</li>
  <li>Jeżeli uważamy, że nasz internet to pociągnie to w <strong>Video Size Limit</strong> nie określamy limitu rozmiaru plików.</li>
  <li>Na koniec najważniejsze, czyli <strong>Debrid Provider</strong>. Wybieramy z listy <strong>RealDebrid</strong> (lub inny wedle uznania) i podajemy <strong>API Private Token</strong>.</li>
  <li>Na samym dole konfiguratora mamy duży fioletowy przycisk <strong>Install</strong>, który przeniesie nas do aplikacji Stremio lub do Stremio Web jeżeli nie mamy aplikacji, i zainstaluje nam dodatek. Natomiast poniżej dużego przycisku znajduje się maly odnośnik <strong>Copy Link</strong>, który wrzuci nam do schowka specjalny link z zakodowaną konfiguracją gotową do ręcznego wklejenia do naszego Stremio.</li>
</ol>

<h3 id="dodatki-na-tv">Dodatki na TV</h3>

<p>W pierwotnej wersji tego wpisu zapomniałem o tym napisać, więc teraz go edytuję, że <strong>z poziomu aplikacji na telewizory nie można edytować dodatków</strong>. Po wejściu w zakładkę Dodatki na telewizorze zobaczymy tylko duży przycisk do wywołania synchronizacji dodatków, które wcześniej zainstalowaliśmy i skonfigurowaliśmy z poziomu przeglądarki lub apliakcji na laptopie lub telefonie/tablecie.</p>

<h2 id="podstawowa-obsługa">Podstawowa obsługa</h2>

<h3 id="wyszukiwanie-seriali-i-filmów">Wyszukiwanie seriali i filmów</h3>

<p>Wystarczy użyć <strong>paska wyszukiwania</strong> lub przeglądać ekran główny (zakładka “Discover” lub “Board”), który – jeśli zainstalowałeś odpowiednie <strong>dodatki katalogujące</strong> – będzie przypominał klasyczny interfejs jak Netflixa czy innych tego typu platform. Mi jako dodatek katalogujący wystarcza (póki co) domyślny <strong><a href="https://v3-cinemeta.strem.io/">Cinemeta</a></strong>.</p>

<h3 id="wybór-odpowiedniego-źródła--pliku-źródłowego-z-listy">Wybór odpowiedniego źródła / pliku źródłowego z listy</h3>

<p>Po wybraniu określonego odcinka serialu wyświetli nam się lista dostępnych opcji. Na tej liście znajdują się wszystkie pozycje jakie zostały zescrapowane (zebrane) <strong>ze wszystkich źródeł</strong>, do których dostęp mają nasze dodatki - Comet, MediaFusion i Torrentio. Są one <strong>posortowane</strong> według dodatku, następnie rozdzielczości, ilości seederów lub rozmiaru itd. <strong>Nie przejmuj się tym zbytnio</strong>. <strong>Po prostu kliknij</strong> pierwszy lepszy jaki wpadnie Ci pod palec, a jeżeli coś będzie z nim nie tak (nie działa, słaba jakość, coś nie tak z dźwiękiem, nie ten język, brak napisów itd.) to po prostu włącz kolejną pozycję z listy.</p>

<p><img src="/images/stremio1.png" alt="Zrzut ekranu Stremio lista seriali" /></p>

<p><img src="/images/stremio2.png" alt="Zrzut ekranu Stremio lista odcinków serialu Picard" /></p>

<h3 id="napisy">Napisy</h3>

<p>Stremio <strong>automatycznie próbuje pobrać napisy</strong> z dodatku OpenSubtitles w języku ustawionym w konfiguracji konta. W trakcie odtwarzania możesz kliknąć ikonę napisów i w locie <strong>zmienić źródło, język lub poprawić synchronizację</strong> (opóźnienie), jeśli napisy rozjeżdżają się z obrazem. Z doświadczenia mogę powiedzieć, że rozjazd napisów często wynika z tego, że są one przygotowane dla filmu / odcinka serialu, w którym nie ma sekcji Previously (z ang. w poprzednim odcinku). Natomiast często odcinki mają ten dodatkowy wstęp. Wtedy <strong>wystarczy opóźnić</strong> (ang. delay) napisy o daną ilość sekund, którą trwa ten fragment. W temacie napisów polecam także <strong>zajrzeć do ustawień Stremio</strong>, bo można tam ustawić <strong>preferowany język napisów</strong> (nie trzeba go zmieniać za każdym razem z X na polski), a także np. czarne lekko transparentne <strong>tło</strong> dla białych napisów itd. Wszystko w zależności jak będzie Ci najwygodniej.</p>

<h3 id="ścieżki-dźwiękowe">Ścieżki dźwiękowe</h3>

<p>Jeśli dany plik posiada wiele ścieżek dźwiękowych (np. oryginalna i polski lektor), obok ikony napisów znajdziesz <strong>ikonę audio</strong>, pozwalającą <strong>płynnie przełączać się między dostępnymi wersjami językowymi</strong>.</p>

<h3 id="synchronizacja">Synchronizacja</h3>

<p>Stremio <strong>synchronizuje informację pomiędzy różnymi urządzeniami</strong> podpiętymi pod to samo konto. I nie mówię tutaj jedynie o bibliotece (ostatnio oglądane, zapisane na później) czy oznaczaniu obejrzanych już odcinków seriali / filmów, ale o tym, że oglądanie można zacząć na telefonie, przesiąść się na komputer, a <strong>odtwarzacz automatycznie zacznie dokładnie w momencie, w którym skończyliśmy</strong> na telefonie. Jest to o tyle szokujące, że można wybrać zupełnie inne źródła - np. na telefonie Comet, na komputerze MediaFusion, a Stremio i tak da sobie z tym radę. Ciekawi mnie jak to działa pod maską. <strong>Stremio jest oprogramowaniem otwartoźródłowym</strong>, więc możliwe, że kiedyś w wolnej chwili zajrzę do kodu.</p>

<h2 id="śledzenie-tego-co-się-obejrzało-trakt">Śledzenie tego co się obejrzało (Trakt)</h2>

<p>Dla osób, które lubią mieć pełną statystykę obejrzanych filmów i seriali, Stremio oferuje <strong>integrację z serwisem <a href="https://trakt.tv/">Trakt.tv</a></strong>. Po sparowaniu kont aplikacja <strong>automatycznie odhacza obejrzane odcinki</strong>. Sam osobiście z tego nie korzystam, bo od wieków jest ze mną aplikacja <strong>TV Time</strong>, a ta nie synchronizuje się (chyba) ze Stremio, ale <strong>wiele osób bardzo chwali Trakt</strong>, dlatego uznałem, że wspomnę o tym.</p>

<h2 id="oszczędności">Oszczędności</h2>

<p>Wydaje mi się, że skutecznie pokazałem, że <strong>Stremio to nie tylko oszczędność na miesięcznych opłatach za serwisy streamingowe, ale też wygoda i niezależność</strong>. Mimo to z kronikarskiego obowiązku zobaczmy sobie ile tak naprawdę miesięcznie jesteśmy w stanie zaoszczędzić dzięki używaniu Stremio.</p>

<p>Sprawdziłem oferty wszystkich popularnych platform streamingowych:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Serwis VOD</th>
      <th style="text-align: left">Najtańszy pakiet</th>
      <th style="text-align: left">Najdroższy pakiet)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong><em>Netflix</em></strong></td>
      <td style="text-align: left">33.00 zł</td>
      <td style="text-align: left">67.00 zł</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>Max (HBO)</em></strong></td>
      <td style="text-align: left">24.92 zł</td>
      <td style="text-align: left">41.58 zł</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>Disney+</em></strong></td>
      <td style="text-align: left">29.16 zł</td>
      <td style="text-align: left">49.99 zł</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>SkyShowtime</em></strong></td>
      <td style="text-align: left">16.67 zł</td>
      <td style="text-align: left">33.25 zł</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>Apple TV+</em></strong></td>
      <td style="text-align: left">34.99 zł</td>
      <td style="text-align: left">34.99 zł</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong><em>Amazon Prime</em></strong></td>
      <td style="text-align: left">5.75 zł</td>
      <td style="text-align: left">5.75 zł</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>SUMA</strong></td>
      <td style="text-align: left"><strong>144.49 zł / msc</strong></td>
      <td style="text-align: left"><strong>232.56 zł / msc</strong></td>
    </tr>
  </tbody>
</table>

<p>Zanim podsumuję powyższą tabelę chciałbym tylko powiedzieć, że są to <strong>ceny aktualne na 6 marca 2026</strong>. Do tego kwoty mogą wydawać się dziwne, ale to tylko dlatego, że <strong>kombinowałem jak zrobić to najtaniej</strong>, czyli w tabeli widać ceny miesięczne np. dla przypadku wzięcia na usługi na cały rok z góry, bo wtedy przeważnie jest taniej średnio o ok. 16% z tego co udało mi się zauważyć u więszkości dostawców.</p>

<p>Jak widać <strong>miesięcznie zaoszczędzamy minimum 144.49 zł</strong>, ale warto wspomnieć, że jest to kwota jaką należałoby płacić za pakiety najgorszej jakości, czyli przeważnie w <strong>marnej rozdzielczości 720p lub wręcz z reklamami</strong>… <strong>Stremio powinno się porównywać raczej do kwoty 232.56 zł</strong> bo taką jakość oferuje, czyli wszystko na maksa. Realny koszt Stremio to tylko subskrypcja Real-Debrid, która w najgorszym przypadku wynosi 4 euro, czyli ok. <strong>17 zł</strong>.</p>

<p>Pomijam już fakt, że <strong>na Stremio można znaleźć produkcje, których nie sposób znaleźć na żadnej z tych sześciu wiodących platform</strong>. Przykładem takiego serialu jest długo poszukiwany przez moją żonę <strong>Schitt’s Creek</strong>, który <strong>nie jest dostępny w ramach żadnego abonamentu</strong> streamingowego w Polsce. Na pewno to nie jedyny taki przypadek.</p>

<h2 id="podsumowanie">Podsumowanie</h2>
<p>Stremio w połączeniu z Real-Debrid to rozwiązanie, które raz skonfigurowane, po prostu działa. Nie jest to już zabawa dla entuzjastów, ale <strong>pełnoprawna, stabilna alternatywa dla rozdrobnionego rynku VOD</strong>. Jeśli przerażają Cię <strong>rosnące ceny abonamentów</strong> i fakt, że ulubione <strong>seriale są rozsiane</strong> po pięciu różnych aplikacjach – daj Stremio szansę. Twoja żona (i portfel) prawdopodobnie Ci za to podziękują. Mówię z doświadczenia.</p>

<p>Masz pytania dotyczące konfiguracji? Śmiało uderzaj do mnie na <a href="https://infosec.exchange/@to3k">Mastodonie</a> lub w sekcji komentarzy poniżej!</p>]]></content><author><name>Tomasz Dunia</name></author><category term="filmy-i-seriale" /><category term="poradniki" /><category term="przemyslenia" /><category term="stremio" /><category term="read-debrid" /><category term="comet" /><category term="mediafusion" /><category term="torrentio" /><category term="netflix" /><category term="hbo" /><category term="disney" /><category term="skyshowtime" /><category term="apple-tv" /><category term="amazon-prime" /><category term="streaming" /><category term="tv" /><category term="series" /><category term="movies" /><category term="seriale" /><category term="filmy" /><summary type="html"><![CDATA[🇵🇱-&gt;🇬🇧 Go to english version of this post / Przejdź do angielskiej wersji tego wpisu]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/stremio.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/stremio.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Desktop Linux for any Android [ENG 🇬🇧]</title><link href="https://blog.tomaszdunia.pl/termux-proot-eng/" rel="alternate" type="text/html" title="Desktop Linux for any Android [ENG 🇬🇧]" /><published>2026-03-04T00:00:00+00:00</published><updated>2026-03-04T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/termux-proot-eng</id><content type="html" xml:base="https://blog.tomaszdunia.pl/termux-proot-eng/"><![CDATA[<p><a href="https://blog.tomaszdunia.pl/termux-proot/">🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post</a></p>

<p>Table of contents:</p>
<ul id="markdown-toc">
  <li><a href="#introduction" id="markdown-toc-introduction">Introduction</a></li>
  <li><a href="#architecture-whats-happening-under-the-hood" id="markdown-toc-architecture-whats-happening-under-the-hood">Architecture: What’s happening under the hood?</a>    <ul>
      <li><a href="#termux---the-terminal-that-is-a-system" id="markdown-toc-termux---the-terminal-that-is-a-system">Termux - the terminal that is a system</a></li>
      <li><a href="#proot---the-safe-sandbox" id="markdown-toc-proot---the-safe-sandbox">PRoot - the safe sandbox</a></li>
      <li><a href="#termux-x11---next-gen-graphics" id="markdown-toc-termux-x11---next-gen-graphics">Termux-X11 - next-gen graphics</a></li>
    </ul>
  </li>
  <li><a href="#hardware-and-software-requirements" id="markdown-toc-hardware-and-software-requirements">Hardware and Software Requirements</a>    <ul>
      <li><a href="#hardware-requirements" id="markdown-toc-hardware-requirements">Hardware Requirements</a></li>
      <li><a href="#necessary-applications" id="markdown-toc-necessary-applications">Necessary Applications</a></li>
    </ul>
  </li>
  <li><a href="#installation-process" id="markdown-toc-installation-process">Installation Process</a>    <ul>
      <li><a href="#step-1---android-configuration" id="markdown-toc-step-1---android-configuration">Step 1 - Android Configuration</a></li>
      <li><a href="#step-2---installing-termux-and-termux-x11" id="markdown-toc-step-2---installing-termux-and-termux-x11">Step 2 - Installing Termux and Termux-X11</a></li>
      <li><a href="#step-3---environment-configuration" id="markdown-toc-step-3---environment-configuration">Step 3 - Environment Configuration</a></li>
      <li><a href="#step-4---launching-the-graphical-environment" id="markdown-toc-step-4---launching-the-graphical-environment">Step 4 - Launching the Graphical Environment</a></li>
    </ul>
  </li>
  <li><a href="#summary" id="markdown-toc-summary">Summary</a></li>
  <li><a href="#video" id="markdown-toc-video">Video</a></li>
</ul>

<h2 id="introduction">Introduction</h2>

<p>Modern smartphones and tablets are powerful computing machines that waste most of their time scrolling through mindless videos. Meanwhile, we carry power comparable to ultrabooks in our pockets. The biggest barrier isn’t the hardware, but the Android operating system, which, while based on the Linux kernel, effectively isolates us from professional tools.</p>

<p>The plan for today is to break that barrier. I will show you how to use the <strong>Termux</strong> environment, the <strong>PRoot</strong> layer, and the <strong>Termux-X11</strong> graphics server to turn <strong>any Android device</strong> into a <strong>full-fledged Linux workstation</strong> with the XFCE desktop. All this <strong>without</strong> unlocking the bootloader and <strong>without</strong> voiding your warranty.</p>

<h2 id="architecture-whats-happening-under-the-hood">Architecture: What’s happening under the hood?</h2>

<p>Before we dive into practice, a little theory. This project stands on three pillars.</p>

<h3 id="termux---the-terminal-that-is-a-system">Termux - the terminal that is a system</h3>

<p><strong>Termux</strong> is not just a simple terminal app. It is a complete <strong>Linux environment</strong> running in the Android user space. It has its own <strong>package manager</strong> <code class="language-plaintext highlighter-rouge">pkg</code>, which allows you to install compilers, interpreters, and networking tools. This is where all the magic happens.</p>

<h3 id="proot---the-safe-sandbox">PRoot - the safe sandbox</h3>
<p>By default, Android does not allow changing the root directory to <code class="language-plaintext highlighter-rouge">/</code> or pretending to be a root user. <strong>PRoot</strong> is a mechanism that intercepts system calls and redirects them so that programs installed inside a container (like Ubuntu or Debian) think they are running on a real, isolated Linux system. This allows for package installation and system management as if you had administrative privileges.</p>

<h3 id="termux-x11---next-gen-graphics">Termux-X11 - next-gen graphics</h3>
<p>Traditionally, Linux on Android was associated with slow VNC connections. <strong>Termux-X11</strong> changes the game. It is a native display server that communicates directly with the Android system. This gives us near-native fluidity, system clipboard support, proper resolution scaling, and—most importantly—the ability to use hardware acceleration on Snapdragon processors.</p>

<h2 id="hardware-and-software-requirements">Hardware and Software Requirements</h2>

<h3 id="hardware-requirements">Hardware Requirements</h3>

<ul>
  <li><strong>Processor</strong> - Snapdragon is best (due to support for Turnip GPU drivers). MediaTek and Google Tensor also work great for development tasks (using software rendering),</li>
  <li><strong>RAM</strong> - Minimum 8 GB. VS Code and modern browsers are memory hogs,</li>
  <li><strong>Disk</strong> - At least 10-15 GB of free space for the system and project files.</li>
</ul>

<h3 id="necessary-applications">Necessary Applications</h3>

<p>The entire process essentially comes down to installing two apps:</p>
<ol>
  <li><strong>Termux</strong> (version 0.118 or newer),</li>
  <li><strong>Termux-X11</strong>.</li>
</ol>

<p>It is recommended <strong>not to download them from the Google Play Store</strong>, where Termux is available in an outdated version. People recommend F-Droid, but I will consistently recommend <strong>Obtainium</strong>, and it is the installation process using the latter that I will describe below.</p>

<h2 id="installation-process">Installation Process</h2>

<h3 id="step-1---android-configuration">Step 1 - Android Configuration</h3>
<p>Android 12 and newer have a mechanism that kills resource-heavy background processes. We need to restrict it:</p>
<ol>
  <li>Go to <strong>Settings -&gt; About Phone</strong>, at the very bottom you will find <strong>Build Number</strong>, tap this field (7 times) until you see the message <strong>You are now a developer</strong>.</li>
  <li>Go to <strong>Settings -&gt; System -&gt; Developer Options</strong>, find the <strong>Apps</strong> section, specifically the option <strong>Disable child process restrictions</strong>, and turn it on.</li>
</ol>

<h3 id="step-2---installing-termux-and-termux-x11">Step 2 - Installing Termux and Termux-X11</h3>

<ol>
  <li>If you don’t already have <strong>Obtainium</strong>, go to the <a href="https://obtainium.imranr.dev/">official website</a>, download the <strong>APK installation file</strong>, and install it on your phone. You may need to grant permission to install apps from third-party (unknown) sources. Additionally, in GrapheneOS, you also need to grant specific app permissions (in this case, the browser) to install other apps. Protip: after installing Obtainium, I recommend revoking this permission from the browser.</li>
  <li>Launch the newly installed Obtainium.</li>
  <li>At the bottom, there is a <strong>+Add App</strong> button.</li>
  <li>In the <strong>App Source URL</strong> field, paste the <a href="https://github.com/termux/termux-app">repository</a> address <code class="language-plaintext highlighter-rouge">https://github.com/termux/termux-app</code>, press the <strong>Add</strong> button.</li>
  <li>The Obtainium app should find the appropriate APK file for your phone itself. Just click <strong>Install</strong> at the bottom.</li>
  <li>We have now installed <strong>Termux</strong>. For <strong>Termux-X11</strong>, the process is identical, just paste the <a href="https://github.com/termux/termux-x11">repository</a> <code class="language-plaintext highlighter-rouge">https://github.com/termux/termux-x11</code> as the repository address.</li>
</ol>

<h3 id="step-3---environment-configuration">Step 3 - Environment Configuration</h3>

<ol>
  <li>Open the <strong>Termux</strong> app. It looks like a standard terminal but running on a phone.</li>
  <li>
    <p>Start by granting it <strong>storage permissions</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> termux-setup-storage
</code></pre></div>    </div>
  </li>
  <li>In the window that pops up, <strong>agree to access</strong>.</li>
  <li>
    <p><strong>Update</strong> the packages:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> apt update <span class="o">&amp;&amp;</span> apt upgrade <span class="nt">-y</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Install</strong> <code class="language-plaintext highlighter-rouge">git</code>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> apt <span class="nb">install </span>git <span class="nt">-y</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>We will now get a <strong>ready-made installation script</strong> from GitHub by a user named <a href="https://github.com/orailnoor">orailnoor</a>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> git clone <span class="o">[</span>https://github.com/orailnoor/termux-linux-setup]<span class="o">(</span>https://github.com/orailnoor/termux-linux-setup<span class="o">)</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Enter</strong> the downloaded repository:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">cd </span>termux-linux-setup/
</code></pre></div>    </div>
  </li>
  <li>
    <p>Inside, besides the <code class="language-plaintext highlighter-rouge">README.md</code> file, there is a <code class="language-plaintext highlighter-rouge">termux-linux-setup.sh</code> script, which we must <strong>grant execution permissions to</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">chmod</span> +x termux-linux-setup.sh
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Run</strong> it:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ./termux-linux-setup.sh
</code></pre></div>    </div>
  </li>
  <li>The launched script will first try to identify which phone it’s running on. As I wrote earlier, it is recommended to have a phone with a Snapdragon processor, specifically an Adreno GPU. However, this is only significant if we wanted to run games on our phone, and I’m not interested in such things. <strong>For VS Code and basic work in a graphical environment, it doesn’t have to be this specific processor family supporting hardware acceleration</strong>.</li>
  <li>Having said that, we must choose the <strong>Desktop Environment</strong> we want to use. I recommend choosing <strong>XFCE</strong>, but everyone can make a choice according to their preferences. So, to choose <code class="language-plaintext highlighter-rouge">XFCE</code> for example, we must enter the digit <strong>1</strong> from the keyboard and confirm with <strong>ENTER</strong>.</li>
  <li>
    <p>This is the moment when we must be <strong>patient</strong>, as this is the core stage of the script’s work. When it is finished, we will receive a large <code class="language-plaintext highlighter-rouge">INSTALLATION COMPLETE!</code> message, and at the end of it, we will find the most important information for us, i.e., <strong>two commands</strong>, the first of which starts the environment and the second stops it:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TO START THE DESKTOP: ./start-linux.sh
TO STOP THE DESKTOP: ./stop-linux.sh
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="step-4---launching-the-graphical-environment">Step 4 - Launching the Graphical Environment</h3>

<ol>
  <li>
    <p>According to the hint from the last point of the previous step, <strong>type the command in Termux</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ./start-linux.sh
</code></pre></div>    </div>
  </li>
  <li>Now we can minimize the Termux app and go to <strong>Termux-X11</strong>.</li>
  <li>After literally a moment of waiting, the <strong>beautiful XFCE interface desktop should appear!</strong></li>
</ol>

<p>At the end of this post, I’m attaching a few <strong>screenshots</strong> showing how it looks <strong>on my Pixel 9a</strong>. It might not look impressive, but it’s worth noting that this is a screen with a diagonal of only 6.3”. Despite this, I think changing a few settings, especially with proper scaling, would change the situation dramatically, and what matters is how smoothly this environment works. The pre-installed Firefox runs on this without any problems even with several tabs open, and I saw that people install and use programs like GIMP, VS Code, and others without problems. For me - WOW!</p>

<p>Interestingly, Termux-X11 is a regular app, so you can <strong>smoothly switch between it and all other applications</strong> you have on your phone.</p>

<h2 id="summary">Summary</h2>

<p>Many people will ask - <code class="language-plaintext highlighter-rouge">okay, but what's this for...?</code>. For me, it is first and foremost a <strong><em>Proof of Concept</em></strong> and an interesting solution. Secondly, I can imagine a quite large number of scenarios where I only have a smartphone with me and it’s necessary to suddenly perform a task that is best, or even only, possible to do in a desktop environment. Thirdly, a monitor and a Bluetooth keyboard and mouse are all you need to create a reasonably comfortable workstation with your entire environment that you have in your pocket - on your smartphone.</p>

<p>After short tests, I started thinking really seriously about getting some reasonably cheap and durable (rugged type) tablet with a large battery and a screen with a diagonal of about 10”. I’ve even already scouted around on the Internet and my attention was caught by the <strong>Ulefone Armor Pad 4 Ultra</strong>. It sounds exotic, but according to many opinions, it’s quite an interesting piece of equipment, and it can be snatched for about 1300 PLN (already including duty). From China, of course.</p>

<hr />

<p><img src="/images/termux1.png" alt="" /></p>

<hr />

<p><img src="/images/termux2.png" alt="" /></p>

<hr />

<p><img src="/images/termux3.png" alt="" /></p>

<hr />

<p><img src="/images/termux4.png" alt="" /></p>

<h2 id="video">Video</h2>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 6px; margin-bottom: 20px;">
  <iframe src="https://www.youtube.com/embed/PyDQmfeRXQc" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>]]></content><author><name>Tomasz Dunia</name></author><category term="tutorials" /><category term="linux" /><category term="android" /><category term="termux" /><category term="x11" /><category term="xfce" /><category term="desktop" /><category term="gui" /><category term="proot" /><summary type="html"><![CDATA[🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post Table of contents: Introduction Architecture: What’s happening under the hood? Termux - the terminal that is a system PRoot - the safe sandbox Termux-X11 - next-gen graphics Hardware and Software Requirements Hardware Requirements Necessary Applications Installation Process Step 1 - Android Configuration Step 2 - Installing Termux and Termux-X11 Step 3 - Environment Configuration Step 4 - Launching the Graphical Environment Summary Video Introduction Modern smartphones and tablets are powerful computing machines that waste most of their time scrolling through mindless videos. Meanwhile, we carry power comparable to ultrabooks in our pockets. The biggest barrier isn’t the hardware, but the Android operating system, which, while based on the Linux kernel, effectively isolates us from professional tools. The plan for today is to break that barrier. I will show you how to use the Termux environment, the PRoot layer, and the Termux-X11 graphics server to turn any Android device into a full-fledged Linux workstation with the XFCE desktop. All this without unlocking the bootloader and without voiding your warranty. Architecture: What’s happening under the hood? Before we dive into practice, a little theory. This project stands on three pillars. Termux - the terminal that is a system Termux is not just a simple terminal app. It is a complete Linux environment running in the Android user space. It has its own package manager pkg, which allows you to install compilers, interpreters, and networking tools. This is where all the magic happens. PRoot - the safe sandbox By default, Android does not allow changing the root directory to / or pretending to be a root user. PRoot is a mechanism that intercepts system calls and redirects them so that programs installed inside a container (like Ubuntu or Debian) think they are running on a real, isolated Linux system. This allows for package installation and system management as if you had administrative privileges. Termux-X11 - next-gen graphics Traditionally, Linux on Android was associated with slow VNC connections. Termux-X11 changes the game. It is a native display server that communicates directly with the Android system. This gives us near-native fluidity, system clipboard support, proper resolution scaling, and—most importantly—the ability to use hardware acceleration on Snapdragon processors. Hardware and Software Requirements Hardware Requirements Processor - Snapdragon is best (due to support for Turnip GPU drivers). MediaTek and Google Tensor also work great for development tasks (using software rendering), RAM - Minimum 8 GB. VS Code and modern browsers are memory hogs, Disk - At least 10-15 GB of free space for the system and project files. Necessary Applications The entire process essentially comes down to installing two apps: Termux (version 0.118 or newer), Termux-X11. It is recommended not to download them from the Google Play Store, where Termux is available in an outdated version. People recommend F-Droid, but I will consistently recommend Obtainium, and it is the installation process using the latter that I will describe below. Installation Process Step 1 - Android Configuration Android 12 and newer have a mechanism that kills resource-heavy background processes. We need to restrict it: Go to Settings -&gt; About Phone, at the very bottom you will find Build Number, tap this field (7 times) until you see the message You are now a developer. Go to Settings -&gt; System -&gt; Developer Options, find the Apps section, specifically the option Disable child process restrictions, and turn it on. Step 2 - Installing Termux and Termux-X11 If you don’t already have Obtainium, go to the official website, download the APK installation file, and install it on your phone. You may need to grant permission to install apps from third-party (unknown) sources. Additionally, in GrapheneOS, you also need to grant specific app permissions (in this case, the browser) to install other apps. Protip: after installing Obtainium, I recommend revoking this permission from the browser. Launch the newly installed Obtainium. At the bottom, there is a +Add App button. In the App Source URL field, paste the repository address https://github.com/termux/termux-app, press the Add button. The Obtainium app should find the appropriate APK file for your phone itself. Just click Install at the bottom. We have now installed Termux. For Termux-X11, the process is identical, just paste the repository https://github.com/termux/termux-x11 as the repository address. Step 3 - Environment Configuration Open the Termux app. It looks like a standard terminal but running on a phone. Start by granting it storage permissions: termux-setup-storage In the window that pops up, agree to access. Update the packages: apt update &amp;&amp; apt upgrade -y Install git: apt install git -y We will now get a ready-made installation script from GitHub by a user named orailnoor: git clone [https://github.com/orailnoor/termux-linux-setup](https://github.com/orailnoor/termux-linux-setup) Enter the downloaded repository: cd termux-linux-setup/ Inside, besides the README.md file, there is a termux-linux-setup.sh script, which we must grant execution permissions to: chmod +x termux-linux-setup.sh Run it: ./termux-linux-setup.sh The launched script will first try to identify which phone it’s running on. As I wrote earlier, it is recommended to have a phone with a Snapdragon processor, specifically an Adreno GPU. However, this is only significant if we wanted to run games on our phone, and I’m not interested in such things. For VS Code and basic work in a graphical environment, it doesn’t have to be this specific processor family supporting hardware acceleration. Having said that, we must choose the Desktop Environment we want to use. I recommend choosing XFCE, but everyone can make a choice according to their preferences. So, to choose XFCE for example, we must enter the digit 1 from the keyboard and confirm with ENTER. This is the moment when we must be patient, as this is the core stage of the script’s work. When it is finished, we will receive a large INSTALLATION COMPLETE! message, and at the end of it, we will find the most important information for us, i.e., two commands, the first of which starts the environment and the second stops it: TO START THE DESKTOP: ./start-linux.sh TO STOP THE DESKTOP: ./stop-linux.sh Step 4 - Launching the Graphical Environment According to the hint from the last point of the previous step, type the command in Termux: ./start-linux.sh Now we can minimize the Termux app and go to Termux-X11. After literally a moment of waiting, the beautiful XFCE interface desktop should appear! At the end of this post, I’m attaching a few screenshots showing how it looks on my Pixel 9a. It might not look impressive, but it’s worth noting that this is a screen with a diagonal of only 6.3”. Despite this, I think changing a few settings, especially with proper scaling, would change the situation dramatically, and what matters is how smoothly this environment works. The pre-installed Firefox runs on this without any problems even with several tabs open, and I saw that people install and use programs like GIMP, VS Code, and others without problems. For me - WOW! Interestingly, Termux-X11 is a regular app, so you can smoothly switch between it and all other applications you have on your phone. Summary Many people will ask - okay, but what's this for...?. For me, it is first and foremost a Proof of Concept and an interesting solution. Secondly, I can imagine a quite large number of scenarios where I only have a smartphone with me and it’s necessary to suddenly perform a task that is best, or even only, possible to do in a desktop environment. Thirdly, a monitor and a Bluetooth keyboard and mouse are all you need to create a reasonably comfortable workstation with your entire environment that you have in your pocket - on your smartphone. After short tests, I started thinking really seriously about getting some reasonably cheap and durable (rugged type) tablet with a large battery and a screen with a diagonal of about 10”. I’ve even already scouted around on the Internet and my attention was caught by the Ulefone Armor Pad 4 Ultra. It sounds exotic, but according to many opinions, it’s quite an interesting piece of equipment, and it can be snatched for about 1300 PLN (already including duty). From China, of course. Video]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/termux-proot.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/termux-proot.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Desktopowy Linux na każdym Androidzie</title><link href="https://blog.tomaszdunia.pl/termux-proot/" rel="alternate" type="text/html" title="Desktopowy Linux na każdym Androidzie" /><published>2026-03-04T00:00:00+00:00</published><updated>2026-03-04T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/termux-proot</id><content type="html" xml:base="https://blog.tomaszdunia.pl/termux-proot/"><![CDATA[<p><a href="https://blog.tomaszdunia.pl/termux-proot-eng/">🇵🇱-&gt;🇬🇧 Go to english version of this post / Przejdź do angielskiej wersji tego wpisu</a></p>

<p>Spis treści:</p>
<ul id="markdown-toc">
  <li><a href="#wstęp" id="markdown-toc-wstęp">Wstęp</a></li>
  <li><a href="#architektura-rozwiązania-co-dzieje-się-pod-maską" id="markdown-toc-architektura-rozwiązania-co-dzieje-się-pod-maską">Architektura rozwiązania: Co dzieje się pod maską?</a>    <ul>
      <li><a href="#termux---terminal-który-jest-systemem" id="markdown-toc-termux---terminal-który-jest-systemem">Termux - terminal, który jest systemem</a></li>
      <li><a href="#proot---bezpieczna-piaskownica" id="markdown-toc-proot---bezpieczna-piaskownica">PRoot - bezpieczna piaskownica</a></li>
      <li><a href="#termux-x11---grafika-nowej-generacji" id="markdown-toc-termux-x11---grafika-nowej-generacji">Termux-X11 - grafika nowej generacji</a></li>
    </ul>
  </li>
  <li><a href="#przygotowanie-sprzętowe-i-programowe" id="markdown-toc-przygotowanie-sprzętowe-i-programowe">Przygotowanie sprzętowe i programowe</a>    <ul>
      <li><a href="#wymagania-sprzętowe" id="markdown-toc-wymagania-sprzętowe">Wymagania sprzętowe</a></li>
      <li><a href="#niezbędne-aplikacje" id="markdown-toc-niezbędne-aplikacje">Niezbędne aplikacje</a></li>
    </ul>
  </li>
  <li><a href="#proces-instalacji" id="markdown-toc-proces-instalacji">Proces instalacji</a>    <ul>
      <li><a href="#krok-1---konfiguracja-androida" id="markdown-toc-krok-1---konfiguracja-androida">Krok 1 - Konfiguracja Androida</a></li>
      <li><a href="#krok-2---instalacja-termux-i-termux-x11" id="markdown-toc-krok-2---instalacja-termux-i-termux-x11">Krok 2 - Instalacja Termux i Termux-X11</a></li>
      <li><a href="#krok-3---konfiguracja-środowiska" id="markdown-toc-krok-3---konfiguracja-środowiska">Krok 3 - Konfiguracja środowiska</a></li>
      <li><a href="#krok-4---uruchomienie-środowiska-graficznego" id="markdown-toc-krok-4---uruchomienie-środowiska-graficznego">Krok 4 - uruchomienie środowiska graficznego</a></li>
    </ul>
  </li>
  <li><a href="#podsumowanie" id="markdown-toc-podsumowanie">Podsumowanie</a></li>
  <li><a href="#wideo" id="markdown-toc-wideo">Wideo</a></li>
</ul>

<h2 id="wstęp">Wstęp</h2>

<p>Współczesne smartfony i tablety to potężne maszyny obliczeniowe, które większość czasu marnują na skrolowanie durnych filmików. Tymczasem w kieszeni nosimy moc porównywalną z ultrabookami. Największą barierą nie jest sprzęt, lecz system operacyjny Android, który choć oparty na jądrze Linux, skutecznie izoluje nas od profesjonalnych narzędzi.</p>

<p>Plan na dzisiaj to przełamanie bariery. Pokażę, jak wykorzystując środowisko <strong>Termux</strong>, warstwę <strong>PRoot</strong> oraz serwer grafiki <strong>Termux-X11</strong>, zmienić <strong>dowolne urządzenie</strong> z Androidem na pokładzie w <strong>pełnoprawną stację roboczą z Linuxem</strong>, środowiskiem XFCE. Wszystko to <strong>bez</strong> odblokowywania bootloadera i <strong>bez</strong> utraty gwarancji.</p>

<h2 id="architektura-rozwiązania-co-dzieje-się-pod-maską">Architektura rozwiązania: Co dzieje się pod maską?</h2>

<p>Zanim przejdziemy do praktyki, trochę teorii. Są trzy filary, na których opiera się ten projekt.</p>

<h3 id="termux---terminal-który-jest-systemem">Termux - terminal, który jest systemem</h3>

<p><strong>Termux</strong> to nie jest zwykła aplikacja terminala. To kompletne <strong>środowisko Linux</strong> działające w przestrzeni użytkownika Androida. Posiada własny <strong>menedżer pakietów</strong> <code class="language-plaintext highlighter-rouge">pkg</code>, który pozwala na instalację kompilatorów, interpreterów i narzędzi sieciowych. To tutaj dzieje się cała magia.</p>

<h3 id="proot---bezpieczna-piaskownica">PRoot - bezpieczna piaskownica</h3>
<p>Standardowo Android nie pozwala na zmianę katalogu głównego na <code class="language-plaintext highlighter-rouge">/</code> ani na udawanie użytkownika root. <strong>PRoot</strong> to mechanizm, który przechwytuje zapytania systemowe (system calls) i przekierowuje je tak, aby programy zainstalowane wewnątrz kontenera (np. Ubuntu czy Debian) myślały, że działają na prawdziwym, odizolowanym systemie Linux. To pozwala na instalację pakietów i zarządzanie systemem tak, jakbyś miał uprawnienia administratora.</p>

<h3 id="termux-x11---grafika-nowej-generacji">Termux-X11 - grafika nowej generacji</h3>
<p>Tradycyjnie Linux na Androidzie kojarzył się z powolnym VNC. <strong>Termux-X11</strong> zmienia zasady gry. To natywny serwer wyświetlania, który komunikuje się bezpośrednio z systemem Android. Dzięki temu uzyskujemy płynność bliską natywnej, wsparcie dla systemowego schowka, poprawne skalowanie rozdzielczości i – co najważniejsze – możliwość korzystania z akceleracji sprzętowej na procesorach Snapdragon.</p>

<h2 id="przygotowanie-sprzętowe-i-programowe">Przygotowanie sprzętowe i programowe</h2>

<h3 id="wymagania-sprzętowe">Wymagania sprzętowe</h3>

<ul>
  <li><strong>Procesor</strong> - najlepiej Snapdragon (ze względu na wsparcie dla sterowników GPU Turnip). MediaTek i Google Tensor również zadziałają świetnie w zadaniach deweloperskich (renderowanie programowe),</li>
  <li><strong>RAM</strong> - minimum 8 GB. VS Code i nowoczesna przeglądarka to pożeracze pamięci,</li>
  <li><strong>Pamięć wewnętrzna</strong> - przynajmniej 10-15 GB wolnej przestrzeni na system i pliki projektów.</li>
</ul>

<h3 id="niezbędne-aplikacje">Niezbędne aplikacje</h3>

<p>Cały proces zamyka się w zasadzie na instalacji dwóch aplikacji:</p>
<ol>
  <li><strong>Termux</strong> (wersja 0.118 lub nowsza),</li>
  <li><strong>Termux-X11</strong>.</li>
</ol>

<p>Zaleca się, aby <strong>nie pobierać ich z Google Play Store</strong>, gdzie Termux jest dostępny w przestarzałej wersji. Ludzie polecają F-Droid, ale ja konsekwentnie będę polecał <strong>Obtainium</strong> i to właśnie proces instalacji wykorzystujący tego drugiego opiszę poniżej.</p>

<h2 id="proces-instalacji">Proces instalacji</h2>

<h3 id="krok-1---konfiguracja-androida">Krok 1 - Konfiguracja Androida</h3>
<p>Android 12 i nowsze posiadają mechanizm, który zabija procesy zużywające dużo zasobów w tle. Musimy go ograniczyć:</p>
<ol>
  <li>Przejdź do <strong>Ustawienia -&gt; Informacje o telefonie</strong>, na samym dole znajdziesz <strong>Numer kompilacji</strong>, klikaj to pole (7 razy), aż zobaczysz komunikat <strong>Jesteś teraz programistą</strong>.</li>
  <li>Przejdź do <strong>Ustawienia -&gt; System -&gt; Opcje programisty</strong>, odszukaj sekcję <strong>Aplikacje</strong>, następnie konkretnie opcję <strong>Wyłącz ograniczenia procesów podrzędnych aplikacji</strong> (ang. <em>Disable child process restrictions</em>) i włącz ją.</li>
</ol>

<h3 id="krok-2---instalacja-termux-i-termux-x11">Krok 2 - Instalacja Termux i Termux-X11</h3>

<ol>
  <li>Jeżeli jeszcze nie posiadasz <strong>Obtainium</strong> to wejdź na <a href="https://obtainium.imranr.dev/">oficjalną stronę</a>, pobierz <strong>plik instalacyjny APK</strong> i zainstaluj na swoim telefonie. Może być tak, że będzie konieczne wyrażenie zgody na instalację aplikacji ze źródeł trzecich (nieznanych). Dodatkowo w GrapheneOS trzeba jeszcze nadać uprawnienia konkretnej aplikacji (w tym przypadku przeglądarce) na instalację innych aplikacji. Protip: po instalacji Obtainium polecam odebrać to uprawnienie przeglądarce.</li>
  <li>Uruchamiamy świeżo zainstalowane Obtainium.</li>
  <li>Na dole znajduje się przycisk <strong>+Dodaj apkę</strong>.</li>
  <li>W pole <strong>Adres URL źródła aplikacji</strong> wklej adres <a href="https://github.com/termux/termux-app">repozytorium</a> <code class="language-plaintext highlighter-rouge">https://github.com/termux/termux-app</code>, naciśnij przycisk <strong>Dodaj</strong>.</li>
  <li>Aplikacja Obtainium powinna sama znaleźć odpowiedni plik APK dla Twojego telefonu. Wystarczy tylko na dole kliknąć <strong>Instaluj</strong>.</li>
  <li>W ten sposób zainstalowaliśmy <strong>Termux</strong>. Dla <strong>Termux-X11</strong> sprawa wygląda analogicznie tylko jako adres repozytorium wklejamy <a href="https://github.com/termux/termux-x11">repozytorium</a> <code class="language-plaintext highlighter-rouge">https://github.com/termux/termux-x11</code>.</li>
</ol>

<h3 id="krok-3---konfiguracja-środowiska">Krok 3 - Konfiguracja środowiska</h3>

<ol>
  <li>Otwieramy aplikację <strong>Termux</strong>. Wygląda ona jak standardowy terminal tylko, że uruchomiony na telefonie.</li>
  <li>
    <p>Zaczynamy od udzielenia jej <strong>uprawnień do pamięci</strong> telefonu:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> termux-setup-storage
</code></pre></div>    </div>
  </li>
  <li>W oknie, które wyskoczy <strong>zgadzamy się na dostęp</strong>.</li>
  <li>
    <p><strong>Zaktualizujmy</strong> pakiety:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> pkg update <span class="o">&amp;&amp;</span> pkg upgrade <span class="nt">-y</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Instalujemy</strong> <code class="language-plaintext highlighter-rouge">git</code>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> pkg <span class="nb">install </span>git <span class="nt">-y</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>Pozyskamy teraz <strong>gotowy skrypt instalacyjny</strong> z GitHuba gościa o nicku <a href="https://github.com/orailnoor">orailnoor</a>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> git clone https://github.com/orailnoor/termux-linux-setup
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Wejdźmy</strong> do pobranego repozytorium:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">cd </span>termux-linux-setup/
</code></pre></div>    </div>
  </li>
  <li>
    <p>W środku oprócz pliku <code class="language-plaintext highlighter-rouge">README.md</code> jest skrypt <code class="language-plaintext highlighter-rouge">termux-linux-setup.sh</code>, któremu musimy <strong>nadać uprawnienia do wykonywania się</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">chmod</span> +x termux-linux-setup.sh
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Odpalmy</strong> go:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ./termux-linux-setup.sh
</code></pre></div>    </div>
  </li>
  <li>Odpalony skrypt w pierwszej kolejności spróbuje identyfikować na jakim telefonie został odpalony. Tak jak wpisałem wcześniej rekomendowane jest posiadanie telefonu z procesorem Snapdragon, a konkretnie z GPU Adreno. Jednakże ma to istotne znaczenie tylko w przypadku, gdybyśmy chcieli odpalić na naszym telefonie gry, a mnie takie rzeczy nie interesują. <strong>Do VS Code i podstawowej pracy na środowisku graficznym nie musi to wcale być ta konkretna rodzina procesorów wspierająca akcelerację sprzętową</strong>.</li>
  <li>Powiedziawszy to, musimy wybrać środowisko graficzne (ang. <em>Desktop Environment</em>), którego chcemy używać. Ja rekomenduje wybranie <strong>XFCE</strong>, ale każdy może dokonać wyboru według własnych preferencji. Zatem, aby dla przykładu wybrać <code class="language-plaintext highlighter-rouge">XFCE</code> musimy wprowadzić z klawiatury cyfrę <strong>1</strong> i potwierdzić <strong>ENTERem</strong>.</li>
  <li>
    <p>To jest ten moment, w którym musimy uzbroić się w <strong>cierpliwość</strong>, bo jest to zasadniczy etap pracy skryptu. Gdy zostanie zakończony otrzymamy duży komunikat <code class="language-plaintext highlighter-rouge">INSTALLATION COMPLETE!</code>, a na jego końcu znajdzie się najważniejsza dla nas informacja, tj. <strong>dwie komendy</strong>, z których pierwsza uruchamia środowisko, a druga zatrzymuje jego pracę:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TO START THE DESKTOP: ./start-linux.sh
TO STOP THE DESKTOP: ./stop-linux.sh
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="krok-4---uruchomienie-środowiska-graficznego">Krok 4 - uruchomienie środowiska graficznego</h3>

<ol>
  <li>
    <p>Zgodnie z podpowiedzią z ostatniego punktu poprzedniego kroku <strong>wpisujemy w Termux komendę</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ./start-linux.sh
</code></pre></div>    </div>
  </li>
  <li>Teraz możemy zminimalizować aplikację Termux i przejść do <strong>Termux-X11</strong>.</li>
  <li>Po dosłownie chwili oczekiwania powinien <strong>ukazać nam się pulpit</strong> pięknego interfejsu XFCE!</li>
</ol>

<p>Na końcu tego wpisu załączam kilka <strong>zrzutów ekranu</strong>, które pokazują jak to wygląda <strong>na moim Pixelu 9a</strong>. Może i nie wygląda to imponująco, ale warto zauważyć, że jest to ekran o przekątnej zaledwie 6.3”. Mimo tego myślę, że zmiana kilku ustawień z odpowiednim skalowaniem na czele zmieniłaby sytuację diametralnie, a to co się liczy to jak płynnie działa to środowisko. Preinstalowany Firefox lata na tym bez problemu nawet z kilkoma kartami, do tego widziałem, że ludzie instalują i używają bez problemu takie programy jak GIMP, VS Code i inne. Jak dla mnie WOW!</p>

<p>Co ciekawe Termux-X11 to zwykła aplikacja, więc można się <strong>płynnie przełączać pomiędzy nią i wszystkimi innymi aplikacjami</strong> jakie ma się na telefonie.</p>

<h2 id="podsumowanie">Podsumowanie</h2>

<p>Wiele osób zapyta - <code class="language-plaintext highlighter-rouge">no dobra, ale po co to komu...?</code>. Dla mnie w pierwszej kolejności jest to <strong><em>Proof of Concept</em></strong> i ciekawe rozwiązanie. Po drugie, jestem w stanie wyobrazić sobie całkiem sporą liczbę scenariuszy, w których mam przy sobie tylko smartfon i konieczne jest nagłe wykonanie jakiegoś zadania, które najlepiej, lub wręcz tylko i wyłącznie, można zrobić na środowisku desktopowym. Po trzecie, monitor oraz klawiaturę i myszkę na Bluetooth to wszystko co jest potrzebne do stworzenia w miarę komfortowego stanowiska pracy z całym swoim środowiskiem, które masz w kieszeni - na swoim smartfonie.</p>

<p>Po krótkich testach zacząłem się zastanawiać naprawdę poważnie nad sprawieniem sobie jakiegoś w miarę taniego i wytrzymałego (typu rugged) tabletu z dużą baterią i ekranem o przekątnej ok. 10”. Poszperałem nawet już trochę w Internecie i moją uwagę przykuł <strong>Ulefone Armor Pad 4 Ultra</strong>. Brzmi egzotycznie, ale według licznych opinii to całkiem ciekawy sprzęt, a można go wyrwać już za jakieś 1300 PLN (wliczając już cło). Oczywiście z Chin.</p>

<hr />

<p><img src="/images/termux1.png" alt="" /></p>

<hr />

<p><img src="/images/termux2.png" alt="" /></p>

<hr />

<p><img src="/images/termux3.png" alt="" /></p>

<hr />

<p><img src="/images/termux4.png" alt="" /></p>

<h2 id="wideo">Wideo</h2>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 6px; margin-bottom: 20px;">
  <iframe src="https://www.youtube.com/embed/PyDQmfeRXQc" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>]]></content><author><name>Tomasz Dunia</name></author><category term="poradniki" /><category term="linux" /><category term="android" /><category term="termux" /><category term="x11" /><category term="xfce" /><category term="desktop" /><category term="gui" /><category term="proot" /><summary type="html"><![CDATA[🇵🇱-&gt;🇬🇧 Go to english version of this post / Przejdź do angielskiej wersji tego wpisu Spis treści: Wstęp Architektura rozwiązania: Co dzieje się pod maską? Termux - terminal, który jest systemem PRoot - bezpieczna piaskownica Termux-X11 - grafika nowej generacji Przygotowanie sprzętowe i programowe Wymagania sprzętowe Niezbędne aplikacje Proces instalacji Krok 1 - Konfiguracja Androida Krok 2 - Instalacja Termux i Termux-X11 Krok 3 - Konfiguracja środowiska Krok 4 - uruchomienie środowiska graficznego Podsumowanie Wideo Wstęp Współczesne smartfony i tablety to potężne maszyny obliczeniowe, które większość czasu marnują na skrolowanie durnych filmików. Tymczasem w kieszeni nosimy moc porównywalną z ultrabookami. Największą barierą nie jest sprzęt, lecz system operacyjny Android, który choć oparty na jądrze Linux, skutecznie izoluje nas od profesjonalnych narzędzi. Plan na dzisiaj to przełamanie bariery. Pokażę, jak wykorzystując środowisko Termux, warstwę PRoot oraz serwer grafiki Termux-X11, zmienić dowolne urządzenie z Androidem na pokładzie w pełnoprawną stację roboczą z Linuxem, środowiskiem XFCE. Wszystko to bez odblokowywania bootloadera i bez utraty gwarancji. Architektura rozwiązania: Co dzieje się pod maską? Zanim przejdziemy do praktyki, trochę teorii. Są trzy filary, na których opiera się ten projekt. Termux - terminal, który jest systemem Termux to nie jest zwykła aplikacja terminala. To kompletne środowisko Linux działające w przestrzeni użytkownika Androida. Posiada własny menedżer pakietów pkg, który pozwala na instalację kompilatorów, interpreterów i narzędzi sieciowych. To tutaj dzieje się cała magia. PRoot - bezpieczna piaskownica Standardowo Android nie pozwala na zmianę katalogu głównego na / ani na udawanie użytkownika root. PRoot to mechanizm, który przechwytuje zapytania systemowe (system calls) i przekierowuje je tak, aby programy zainstalowane wewnątrz kontenera (np. Ubuntu czy Debian) myślały, że działają na prawdziwym, odizolowanym systemie Linux. To pozwala na instalację pakietów i zarządzanie systemem tak, jakbyś miał uprawnienia administratora. Termux-X11 - grafika nowej generacji Tradycyjnie Linux na Androidzie kojarzył się z powolnym VNC. Termux-X11 zmienia zasady gry. To natywny serwer wyświetlania, który komunikuje się bezpośrednio z systemem Android. Dzięki temu uzyskujemy płynność bliską natywnej, wsparcie dla systemowego schowka, poprawne skalowanie rozdzielczości i – co najważniejsze – możliwość korzystania z akceleracji sprzętowej na procesorach Snapdragon. Przygotowanie sprzętowe i programowe Wymagania sprzętowe Procesor - najlepiej Snapdragon (ze względu na wsparcie dla sterowników GPU Turnip). MediaTek i Google Tensor również zadziałają świetnie w zadaniach deweloperskich (renderowanie programowe), RAM - minimum 8 GB. VS Code i nowoczesna przeglądarka to pożeracze pamięci, Pamięć wewnętrzna - przynajmniej 10-15 GB wolnej przestrzeni na system i pliki projektów. Niezbędne aplikacje Cały proces zamyka się w zasadzie na instalacji dwóch aplikacji: Termux (wersja 0.118 lub nowsza), Termux-X11. Zaleca się, aby nie pobierać ich z Google Play Store, gdzie Termux jest dostępny w przestarzałej wersji. Ludzie polecają F-Droid, ale ja konsekwentnie będę polecał Obtainium i to właśnie proces instalacji wykorzystujący tego drugiego opiszę poniżej. Proces instalacji Krok 1 - Konfiguracja Androida Android 12 i nowsze posiadają mechanizm, który zabija procesy zużywające dużo zasobów w tle. Musimy go ograniczyć: Przejdź do Ustawienia -&gt; Informacje o telefonie, na samym dole znajdziesz Numer kompilacji, klikaj to pole (7 razy), aż zobaczysz komunikat Jesteś teraz programistą. Przejdź do Ustawienia -&gt; System -&gt; Opcje programisty, odszukaj sekcję Aplikacje, następnie konkretnie opcję Wyłącz ograniczenia procesów podrzędnych aplikacji (ang. Disable child process restrictions) i włącz ją. Krok 2 - Instalacja Termux i Termux-X11 Jeżeli jeszcze nie posiadasz Obtainium to wejdź na oficjalną stronę, pobierz plik instalacyjny APK i zainstaluj na swoim telefonie. Może być tak, że będzie konieczne wyrażenie zgody na instalację aplikacji ze źródeł trzecich (nieznanych). Dodatkowo w GrapheneOS trzeba jeszcze nadać uprawnienia konkretnej aplikacji (w tym przypadku przeglądarce) na instalację innych aplikacji. Protip: po instalacji Obtainium polecam odebrać to uprawnienie przeglądarce. Uruchamiamy świeżo zainstalowane Obtainium. Na dole znajduje się przycisk +Dodaj apkę. W pole Adres URL źródła aplikacji wklej adres repozytorium https://github.com/termux/termux-app, naciśnij przycisk Dodaj. Aplikacja Obtainium powinna sama znaleźć odpowiedni plik APK dla Twojego telefonu. Wystarczy tylko na dole kliknąć Instaluj. W ten sposób zainstalowaliśmy Termux. Dla Termux-X11 sprawa wygląda analogicznie tylko jako adres repozytorium wklejamy repozytorium https://github.com/termux/termux-x11. Krok 3 - Konfiguracja środowiska Otwieramy aplikację Termux. Wygląda ona jak standardowy terminal tylko, że uruchomiony na telefonie. Zaczynamy od udzielenia jej uprawnień do pamięci telefonu: termux-setup-storage W oknie, które wyskoczy zgadzamy się na dostęp. Zaktualizujmy pakiety: pkg update &amp;&amp; pkg upgrade -y Instalujemy git: pkg install git -y Pozyskamy teraz gotowy skrypt instalacyjny z GitHuba gościa o nicku orailnoor: git clone https://github.com/orailnoor/termux-linux-setup Wejdźmy do pobranego repozytorium: cd termux-linux-setup/ W środku oprócz pliku README.md jest skrypt termux-linux-setup.sh, któremu musimy nadać uprawnienia do wykonywania się: chmod +x termux-linux-setup.sh Odpalmy go: ./termux-linux-setup.sh Odpalony skrypt w pierwszej kolejności spróbuje identyfikować na jakim telefonie został odpalony. Tak jak wpisałem wcześniej rekomendowane jest posiadanie telefonu z procesorem Snapdragon, a konkretnie z GPU Adreno. Jednakże ma to istotne znaczenie tylko w przypadku, gdybyśmy chcieli odpalić na naszym telefonie gry, a mnie takie rzeczy nie interesują. Do VS Code i podstawowej pracy na środowisku graficznym nie musi to wcale być ta konkretna rodzina procesorów wspierająca akcelerację sprzętową. Powiedziawszy to, musimy wybrać środowisko graficzne (ang. Desktop Environment), którego chcemy używać. Ja rekomenduje wybranie XFCE, ale każdy może dokonać wyboru według własnych preferencji. Zatem, aby dla przykładu wybrać XFCE musimy wprowadzić z klawiatury cyfrę 1 i potwierdzić ENTERem. To jest ten moment, w którym musimy uzbroić się w cierpliwość, bo jest to zasadniczy etap pracy skryptu. Gdy zostanie zakończony otrzymamy duży komunikat INSTALLATION COMPLETE!, a na jego końcu znajdzie się najważniejsza dla nas informacja, tj. dwie komendy, z których pierwsza uruchamia środowisko, a druga zatrzymuje jego pracę: TO START THE DESKTOP: ./start-linux.sh TO STOP THE DESKTOP: ./stop-linux.sh Krok 4 - uruchomienie środowiska graficznego Zgodnie z podpowiedzią z ostatniego punktu poprzedniego kroku wpisujemy w Termux komendę: ./start-linux.sh Teraz możemy zminimalizować aplikację Termux i przejść do Termux-X11. Po dosłownie chwili oczekiwania powinien ukazać nam się pulpit pięknego interfejsu XFCE! Na końcu tego wpisu załączam kilka zrzutów ekranu, które pokazują jak to wygląda na moim Pixelu 9a. Może i nie wygląda to imponująco, ale warto zauważyć, że jest to ekran o przekątnej zaledwie 6.3”. Mimo tego myślę, że zmiana kilku ustawień z odpowiednim skalowaniem na czele zmieniłaby sytuację diametralnie, a to co się liczy to jak płynnie działa to środowisko. Preinstalowany Firefox lata na tym bez problemu nawet z kilkoma kartami, do tego widziałem, że ludzie instalują i używają bez problemu takie programy jak GIMP, VS Code i inne. Jak dla mnie WOW! Co ciekawe Termux-X11 to zwykła aplikacja, więc można się płynnie przełączać pomiędzy nią i wszystkimi innymi aplikacjami jakie ma się na telefonie. Podsumowanie Wiele osób zapyta - no dobra, ale po co to komu...?. Dla mnie w pierwszej kolejności jest to Proof of Concept i ciekawe rozwiązanie. Po drugie, jestem w stanie wyobrazić sobie całkiem sporą liczbę scenariuszy, w których mam przy sobie tylko smartfon i konieczne jest nagłe wykonanie jakiegoś zadania, które najlepiej, lub wręcz tylko i wyłącznie, można zrobić na środowisku desktopowym. Po trzecie, monitor oraz klawiaturę i myszkę na Bluetooth to wszystko co jest potrzebne do stworzenia w miarę komfortowego stanowiska pracy z całym swoim środowiskiem, które masz w kieszeni - na swoim smartfonie. Po krótkich testach zacząłem się zastanawiać naprawdę poważnie nad sprawieniem sobie jakiegoś w miarę taniego i wytrzymałego (typu rugged) tabletu z dużą baterią i ekranem o przekątnej ok. 10”. Poszperałem nawet już trochę w Internecie i moją uwagę przykuł Ulefone Armor Pad 4 Ultra. Brzmi egzotycznie, ale według licznych opinii to całkiem ciekawy sprzęt, a można go wyrwać już za jakieś 1300 PLN (wliczając już cło). Oczywiście z Chin. Wideo]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/termux-proot.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/termux-proot.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Motorola + GrapheneOS!</title><link href="https://blog.tomaszdunia.pl/motorola-grapheneos/" rel="alternate" type="text/html" title="Motorola + GrapheneOS!" /><published>2026-03-03T00:00:00+00:00</published><updated>2026-03-03T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/motorola-grapheneos</id><content type="html" xml:base="https://blog.tomaszdunia.pl/motorola-grapheneos/"><![CDATA[<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NOTE: English version of this post is available below.
</code></pre></div></div>

<p>Dawno już nie pisałem żadnego szorta, bo wpisy w krótkiej formie to zdecydowanie nie moja bajka. Poza tym ja wolę zgłębić temat, rozebrać na części pierwsze i następnie na spokojnie opisać. Czasem jednak trafi się news, który sprawi, że moje serduszko zabije odrobinę szybciej i to właśnie jest ten moment.</p>

<p>Robiąc poranny przegląd prasy natrafiłem na notatkę prasową, której tytuł zaczynał się <strong><em>Motorola announces a partnership with GrapheneOS Foundation…</em></strong>. Nie ma wątplwiości, że jest to łamiąca informacja (nieudolnie zapożyczone z angielskiego - <em>Breaking News</em>).</p>

<h2 id="nota-prasowa">Nota prasowa</h2>

<p>Oryginalną treść notatki można przeczytać <a href="https://motorolanews.com/motorola-three-new-b2b-solutions-at-mwc-2026/">tutaj</a>, ale nas w zasadzie interesuje tylko:</p>

<blockquote>
  <h2 id="motorola-ogłasza-partnerstwo-z-grapheneos-foundation-otwierając-nowy-rozdział-w-bezpieczeństwie-smartfonów-i-rozszerzając-ofertę-dla-przedsiębiorstw">Motorola ogłasza partnerstwo z GrapheneOS Foundation, otwierając nowy rozdział w bezpieczeństwie smartfonów i rozszerzając ofertę dla przedsiębiorstw</h2>

  <p><strong><em>2 marca 2026 r.</em></strong></p>

  <p>Podczas tegorocznych targów Mobile World Congress (MWC), Motorola (spółka należąca do Lenovo) ogłosiła wprowadzenie nowych rozwiązań dla konsumentów i firm. Kluczowym punktem ogłoszenia jest <strong>nawiązanie współpracy z GrapheneOS Foundation</strong>, której celem jest zapewnienie najnowocześniejszych zabezpieczeń użytkownikom na całym świecie. Ponadto Motorola zaprezentowała funkcję Private Image Data w ramach aplikacji Moto Secure oraz platformę Moto Analytics, co znacząco rozszerza ekosystem B2B o zaawansowaną ochronę i głęboki wgląd operacyjny dla organizacji z różnych branż.</p>

  <h3 id="partnerstwo-z-grapheneos-foundation">Partnerstwo z GrapheneOS Foundation</h3>

  <p>Motorola zapowiada <strong>nową erę bezpieczeństwa smartfonów dzięki długoterminowej współpracy z GrapheneOS Foundation</strong> – wiodącą organizacją non-profit zajmującą się zaawansowanym bezpieczeństwem mobilnym i twórcami utwardzonego systemu operacyjnego opartego na Android Open Source Project (AOSP). Obie strony będą wspólnie pracować nad wzmocnieniem bezpieczeństwa smartfonów oraz kolaborować <strong>przy tworzeniu przyszłych urządzeń zaprojektowanych z myślą o pełnej kompatybilności z GrapheneOS</strong>.</p>

  <p>„Jesteśmy dumni z partnerstwa z Motorolą, dzięki któremu dostarczymy wiodący w branży, skoncentrowany na prywatności i bezpieczeństwie system operacyjny <strong>GrapheneOS do ich smartfonów nowej generacji</strong>” – przekazał rzecznik GrapheneOS. „Ta współpraca to kamień milowy w rozszerzaniu zasięgu GrapheneOS. Doceniamy Motorolę za wykonanie tego znaczącego kroku w stronę rozwoju bezpieczeństwa mobilnego”.</p>

  <p>Współpraca ta połączy pionierską inżynierię GrapheneOS z wieloletnim doświadczeniem Motoroli w dziedzinie bezpieczeństwa oraz rozwiązaniami Lenovo ThinkShield. W nadchodzących miesiącach planowane są wspólne badania oraz rozwój nowych funkcji programowych.</p>
</blockquote>

<h2 id="mój-komentarz">Mój komentarz</h2>

<p>Mój komentarz do tego będzie stosunkowo krótki. Marka Motorola była niegdyś <strong>niewątpliwą potęgą</strong>. Mówimy tutaj o czasach <strong>początków mobilnej telefonii komórkowej</strong>. Później Motka zaliczyła zjazd z kilkoma drobnymi wzlotami po drodze. Nie jestem do końca ekspertem w temacie Motoroli, ale wydaje mi się, że aktualnie jest to <strong>całkiem rozsądny sprzęt za niewygórowaną cenę</strong>, jednakże jest to na pewno dalekie od szczytowej formy tej firmy. Wydaje się, że aby wrócić do historycznego blasku potrzebne jest <strong>coś nowatorskiego</strong> i może być tak, że to właśnie współpraca z GrapheneOS to będzie właśnie to.</p>

<p>Motorola to <strong>porządny sprzęt</strong>, a GrapheneOS to <strong>system, który używam i szanuję</strong>. Takie połączenie może być <strong>silnie wybuchowe</strong>. Problem w tym, że może to być wybuch zarówno na dobre jak i na złe.</p>

<p>Na pewno będę obserwował tę fuzję i kibicował temu projektowi z wypiekami na twarzy. <strong>Jeżeli to się uda to moim następnym telefonem prawie na pewno będzie Motorola</strong>.</p>

<p>Ale czy na rynku jest jeszcze miejsce dla trzeciego systemu? Do tej pory wszystkie systemy poza iOS i Android <strong>poniosły sromotną klęskę</strong> i tak samo może być w tym przypadku. Jeżeli to nie pyknie to Motorola straci swoją (raczej) ostatnią szansę i prawdopodobnie będzie to <strong>koniec tej marki</strong>. Natomiast porażka dla GrapheneOS będzie <strong>jeszcze bardziej sromotna</strong>, bo zakładam, że po tym jak już dogadali się z Motorolą zaczną po macoszemu traktować rozwijanie systemu pod Pixele, które do tej pory były <strong>trzonem całego projektu</strong>. W ten sposób trafiamy aktualnie w okres przejściowy, gdy nowe rozwiązanie nie jest jeszcze gotowe, a stare przestaje być wspierane w 100%, ale musimy jeszcze na nim przetrwać parę miesięcy. Jeżeli finalizacja tej współpracy okaże się szczytem nie do przejścia to <strong>zostaniemy bez GrapheneOS zarówno na Motorole jak i Pixele</strong>. Obym się mylił i oby za tym projektem stały jedynie osoby, które wiedzą co robią i doprowadzą to do szczęśliwego końca. Życzę tego sobie i Wam.</p>

<hr />
<hr />

<p>It’s been a while since I’ve written a “short,” as short-form posts are definitely not my thing. Besides, I prefer to delve into a topic, take it apart, and then describe it at my own pace. Sometimes, however, a piece of news comes along that makes my heart beat a little faster, and this is exactly that moment.</p>

<p>While doing my morning press review, I came across a press release whose title began with <strong><em>Motorola announces a partnership with GrapheneOS Foundation…</em></strong>. There is no doubt that this is <strong><em>Breaking News</em></strong>.</p>

<h2 id="press-release">Press Release</h2>

<p>The original content of the note can be read <a href="https://motorolanews.com/motorola-three-new-b2b-solutions-at-mwc-2026/">here</a>, but we are essentially only interested in:</p>

<blockquote>
  <h2 id="motorola-announces-a-partnership-with-grapheneos-foundation-marking-a-new-chapter-in-smartphone-security-and-expanding-its-enterprise-portfolio">Motorola announces a partnership with GrapheneOS Foundation, marking a new chapter in smartphone security and expanding its enterprise portfolio</h2>

  <p><strong><em>March 2, 2026</em></strong></p>

  <p>Motorola, a Lenovo Company, announced the addition of new consumer and enterprise solutions to its portfolio today at Mobile World Congress. The company unveiled a <strong>partnership with the GrapheneOS Foundation</strong>, to bring cutting-edge security to everyday users across the globe. In addition, Motorola introduced a new Moto Secure feature and Moto Analytics, to expand Motorola’s B2B ecosystem with advanced security and deeper operational insights for organizations across industries. These announcements reinforce Motorola’s commitment to delivering intelligent, and highly capable technology with enhanced security for customers worldwide.</p>

  <h3 id="grapheneos-foundation-partnership">GrapheneOS Foundation Partnership</h3>

  <p>Motorola is introducing a <strong>new era of smartphone security through a long‑term partnership with the GrapheneOS Foundation</strong>, the leading nonprofit in advanced mobile security and creators of a hardened, operating system based on the Android Open Source Project. Together, Motorola and the GrapheneOS Foundation will work to strengthen smartphone security and <strong>collaborate on future devices engineered with GrapheneOS compatibility</strong>.</p>

  <p>“We are thrilled to be partnering with Motorola to bring GrapheneOS’s industry‑leading privacy and security‑focused mobile <strong>operating system to their next-generation smartphone</strong>”, said a spokesperson at GrapheneOS. “This collaboration marks a significant milestone in expanding the reach of GrapheneOS, and we applaud Motorola for taking this meaningful step towards advancing mobile security.”</p>

  <p>By combining GrapheneOS’s pioneering engineering with Motorola’s decades of security expertise, real‑world user insights, and Lenovo’s ThinkShield solutions, the collaboration will advance a new generation of privacy and security technologies. In the coming months, Motorola and the GrapheneOS Foundation will continue to collaborate on joint research, software enhancements, and new security capabilities, with more details and solutions to roll out as the partnership evolves.</p>
</blockquote>

<h2 id="my-comment">My comment</h2>

<p>My comment on this will be relatively brief. The Motorola brand was once an <strong>unquestionable powerhouse</strong>. We’re talking about the <strong>early days of mobile telephony</strong>. Later, Motorola experienced a decline with a few minor ups along the way. I’m not exactly an expert on Motorola, but it seems to me that currently, they offer <strong>quite reasonable hardware for an affordable price</strong>, but it is certainly far from the company’s peak form. It seems that to return to its historical glory, <strong>something innovative</strong> is needed, and it could be that the partnership with GrapheneOS will be exactly that.</p>

<p>Motorola is <strong>decent hardware</strong>, and GrapheneOS is a <strong>system I use and respect</strong>. Such a combination could be <strong>highly explosive</strong>. The problem is that it could be an explosion for better or for worse.</p>

<p>I will definitely be watching this fusion and rooting for this project with bated breath. <strong>If it succeeds, my next phone will almost certainly be a Motorola.</strong></p>

<p>But is there still room in the market for a third system? So far, every system besides iOS and Android has <strong>suffered a crushing defeat</strong>, and the same could happen here. If this doesn’t work out, Motorola will lose what is (likely) its last chance, and it will probably be the <strong>end of this brand</strong>. Meanwhile, a failure for GrapheneOS would be <strong>even more disastrous</strong>, as I assume that after striking a deal with Motorola, they might start neglecting the development of the system for Pixels, which have been the <strong>backbone of the entire project</strong> so far. Thus, we are currently entering a transition period where the new solution isn’t ready yet, and the old one stops being 100% supported, but we still have to survive on it for a few months. If finalizing this partnership turns out to be an insurmountable peak, <strong>we will be left without GrapheneOS on both Motorolas and Pixels</strong>. I hope I’m wrong and that there are only people behind this project who know what they’re doing and will bring it to a happy conclusion. I wish that for myself and for you.</p>]]></content><author><name>Tomasz Dunia</name></author><category term="shorts" /><category term="szorty" /><category term="motorola" /><category term="grapheneos" /><category term="android" /><category term="privacy" /><summary type="html"><![CDATA[NOTE: English version of this post is available below. Dawno już nie pisałem żadnego szorta, bo wpisy w krótkiej formie to zdecydowanie nie moja bajka. Poza tym ja wolę zgłębić temat, rozebrać na części pierwsze i następnie na spokojnie opisać. Czasem jednak trafi się news, który sprawi, że moje serduszko zabije odrobinę szybciej i to właśnie jest ten moment. Robiąc poranny przegląd prasy natrafiłem na notatkę prasową, której tytuł zaczynał się Motorola announces a partnership with GrapheneOS Foundation…. Nie ma wątplwiości, że jest to łamiąca informacja (nieudolnie zapożyczone z angielskiego - Breaking News). Nota prasowa Oryginalną treść notatki można przeczytać tutaj, ale nas w zasadzie interesuje tylko: Motorola ogłasza partnerstwo z GrapheneOS Foundation, otwierając nowy rozdział w bezpieczeństwie smartfonów i rozszerzając ofertę dla przedsiębiorstw 2 marca 2026 r. Podczas tegorocznych targów Mobile World Congress (MWC), Motorola (spółka należąca do Lenovo) ogłosiła wprowadzenie nowych rozwiązań dla konsumentów i firm. Kluczowym punktem ogłoszenia jest nawiązanie współpracy z GrapheneOS Foundation, której celem jest zapewnienie najnowocześniejszych zabezpieczeń użytkownikom na całym świecie. Ponadto Motorola zaprezentowała funkcję Private Image Data w ramach aplikacji Moto Secure oraz platformę Moto Analytics, co znacząco rozszerza ekosystem B2B o zaawansowaną ochronę i głęboki wgląd operacyjny dla organizacji z różnych branż. Partnerstwo z GrapheneOS Foundation Motorola zapowiada nową erę bezpieczeństwa smartfonów dzięki długoterminowej współpracy z GrapheneOS Foundation – wiodącą organizacją non-profit zajmującą się zaawansowanym bezpieczeństwem mobilnym i twórcami utwardzonego systemu operacyjnego opartego na Android Open Source Project (AOSP). Obie strony będą wspólnie pracować nad wzmocnieniem bezpieczeństwa smartfonów oraz kolaborować przy tworzeniu przyszłych urządzeń zaprojektowanych z myślą o pełnej kompatybilności z GrapheneOS. „Jesteśmy dumni z partnerstwa z Motorolą, dzięki któremu dostarczymy wiodący w branży, skoncentrowany na prywatności i bezpieczeństwie system operacyjny GrapheneOS do ich smartfonów nowej generacji” – przekazał rzecznik GrapheneOS. „Ta współpraca to kamień milowy w rozszerzaniu zasięgu GrapheneOS. Doceniamy Motorolę za wykonanie tego znaczącego kroku w stronę rozwoju bezpieczeństwa mobilnego”. Współpraca ta połączy pionierską inżynierię GrapheneOS z wieloletnim doświadczeniem Motoroli w dziedzinie bezpieczeństwa oraz rozwiązaniami Lenovo ThinkShield. W nadchodzących miesiącach planowane są wspólne badania oraz rozwój nowych funkcji programowych. Mój komentarz Mój komentarz do tego będzie stosunkowo krótki. Marka Motorola była niegdyś niewątpliwą potęgą. Mówimy tutaj o czasach początków mobilnej telefonii komórkowej. Później Motka zaliczyła zjazd z kilkoma drobnymi wzlotami po drodze. Nie jestem do końca ekspertem w temacie Motoroli, ale wydaje mi się, że aktualnie jest to całkiem rozsądny sprzęt za niewygórowaną cenę, jednakże jest to na pewno dalekie od szczytowej formy tej firmy. Wydaje się, że aby wrócić do historycznego blasku potrzebne jest coś nowatorskiego i może być tak, że to właśnie współpraca z GrapheneOS to będzie właśnie to. Motorola to porządny sprzęt, a GrapheneOS to system, który używam i szanuję. Takie połączenie może być silnie wybuchowe. Problem w tym, że może to być wybuch zarówno na dobre jak i na złe. Na pewno będę obserwował tę fuzję i kibicował temu projektowi z wypiekami na twarzy. Jeżeli to się uda to moim następnym telefonem prawie na pewno będzie Motorola. Ale czy na rynku jest jeszcze miejsce dla trzeciego systemu? Do tej pory wszystkie systemy poza iOS i Android poniosły sromotną klęskę i tak samo może być w tym przypadku. Jeżeli to nie pyknie to Motorola straci swoją (raczej) ostatnią szansę i prawdopodobnie będzie to koniec tej marki. Natomiast porażka dla GrapheneOS będzie jeszcze bardziej sromotna, bo zakładam, że po tym jak już dogadali się z Motorolą zaczną po macoszemu traktować rozwijanie systemu pod Pixele, które do tej pory były trzonem całego projektu. W ten sposób trafiamy aktualnie w okres przejściowy, gdy nowe rozwiązanie nie jest jeszcze gotowe, a stare przestaje być wspierane w 100%, ale musimy jeszcze na nim przetrwać parę miesięcy. Jeżeli finalizacja tej współpracy okaże się szczytem nie do przejścia to zostaniemy bez GrapheneOS zarówno na Motorole jak i Pixele. Obym się mylił i oby za tym projektem stały jedynie osoby, które wiedzą co robią i doprowadzą to do szczęśliwego końca. Życzę tego sobie i Wam. It’s been a while since I’ve written a “short,” as short-form posts are definitely not my thing. Besides, I prefer to delve into a topic, take it apart, and then describe it at my own pace. Sometimes, however, a piece of news comes along that makes my heart beat a little faster, and this is exactly that moment. While doing my morning press review, I came across a press release whose title began with Motorola announces a partnership with GrapheneOS Foundation…. There is no doubt that this is Breaking News. Press Release The original content of the note can be read here, but we are essentially only interested in: Motorola announces a partnership with GrapheneOS Foundation, marking a new chapter in smartphone security and expanding its enterprise portfolio March 2, 2026 Motorola, a Lenovo Company, announced the addition of new consumer and enterprise solutions to its portfolio today at Mobile World Congress. The company unveiled a partnership with the GrapheneOS Foundation, to bring cutting-edge security to everyday users across the globe. In addition, Motorola introduced a new Moto Secure feature and Moto Analytics, to expand Motorola’s B2B ecosystem with advanced security and deeper operational insights for organizations across industries. These announcements reinforce Motorola’s commitment to delivering intelligent, and highly capable technology with enhanced security for customers worldwide. GrapheneOS Foundation Partnership Motorola is introducing a new era of smartphone security through a long‑term partnership with the GrapheneOS Foundation, the leading nonprofit in advanced mobile security and creators of a hardened, operating system based on the Android Open Source Project. Together, Motorola and the GrapheneOS Foundation will work to strengthen smartphone security and collaborate on future devices engineered with GrapheneOS compatibility. “We are thrilled to be partnering with Motorola to bring GrapheneOS’s industry‑leading privacy and security‑focused mobile operating system to their next-generation smartphone”, said a spokesperson at GrapheneOS. “This collaboration marks a significant milestone in expanding the reach of GrapheneOS, and we applaud Motorola for taking this meaningful step towards advancing mobile security.” By combining GrapheneOS’s pioneering engineering with Motorola’s decades of security expertise, real‑world user insights, and Lenovo’s ThinkShield solutions, the collaboration will advance a new generation of privacy and security technologies. In the coming months, Motorola and the GrapheneOS Foundation will continue to collaborate on joint research, software enhancements, and new security capabilities, with more details and solutions to roll out as the partnership evolves. My comment My comment on this will be relatively brief. The Motorola brand was once an unquestionable powerhouse. We’re talking about the early days of mobile telephony. Later, Motorola experienced a decline with a few minor ups along the way. I’m not exactly an expert on Motorola, but it seems to me that currently, they offer quite reasonable hardware for an affordable price, but it is certainly far from the company’s peak form. It seems that to return to its historical glory, something innovative is needed, and it could be that the partnership with GrapheneOS will be exactly that. Motorola is decent hardware, and GrapheneOS is a system I use and respect. Such a combination could be highly explosive. The problem is that it could be an explosion for better or for worse. I will definitely be watching this fusion and rooting for this project with bated breath. If it succeeds, my next phone will almost certainly be a Motorola. But is there still room in the market for a third system? So far, every system besides iOS and Android has suffered a crushing defeat, and the same could happen here. If this doesn’t work out, Motorola will lose what is (likely) its last chance, and it will probably be the end of this brand. Meanwhile, a failure for GrapheneOS would be even more disastrous, as I assume that after striking a deal with Motorola, they might start neglecting the development of the system for Pixels, which have been the backbone of the entire project so far. Thus, we are currently entering a transition period where the new solution isn’t ready yet, and the old one stops being 100% supported, but we still have to survive on it for a few months. If finalizing this partnership turns out to be an insurmountable peak, we will be left without GrapheneOS on both Motorolas and Pixels. I hope I’m wrong and that there are only people behind this project who know what they’re doing and will bring it to a happy conclusion. I wish that for myself and for you.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/motorola-grapheneos.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/motorola-grapheneos.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">OpenClaw + OpenRouter [ENG 🇬🇧]</title><link href="https://blog.tomaszdunia.pl/openrouter-eng/" rel="alternate" type="text/html" title="OpenClaw + OpenRouter [ENG 🇬🇧]" /><published>2026-02-26T00:00:00+00:00</published><updated>2026-02-26T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/openrouter-eng</id><content type="html" xml:base="https://blog.tomaszdunia.pl/openrouter-eng/"><![CDATA[<p><a href="https://blog.tomaszdunia.pl/openrouter/">🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post</a></p>

<p>Table of contents:</p>
<ul id="markdown-toc">
  <li><a href="#introduction" id="markdown-toc-introduction">Introduction</a></li>
  <li><a href="#what-is-openrouter" id="markdown-toc-what-is-openrouter">What is OpenRouter</a></li>
  <li><a href="#registration" id="markdown-toc-registration">Registration</a></li>
  <li><a href="#topping-up-the-account" id="markdown-toc-topping-up-the-account">Topping up the account</a></li>
  <li><a href="#bot-optimization" id="markdown-toc-bot-optimization">Bot Optimization</a>    <ul>
      <li><a href="#editing-personality-files" id="markdown-toc-editing-personality-files">Editing personality files</a>        <ul>
          <li><a href="#agentsmd" id="markdown-toc-agentsmd">AGENTS.md</a></li>
          <li><a href="#soulmd" id="markdown-toc-soulmd">SOUL.md</a></li>
          <li><a href="#toolsmd" id="markdown-toc-toolsmd">TOOLS.md</a></li>
          <li><a href="#identitymd" id="markdown-toc-identitymd">IDENTITY.md</a></li>
          <li><a href="#usermd" id="markdown-toc-usermd">USER.md</a></li>
          <li><a href="#heartbeatmd" id="markdown-toc-heartbeatmd">HEARTBEAT.md</a></li>
          <li><a href="#bootstrapmd" id="markdown-toc-bootstrapmd">BOOTSTRAP.md</a></li>
          <li><a href="#memorymd" id="markdown-toc-memorymd">MEMORY.md</a></li>
          <li><a href="#pro-tip" id="markdown-toc-pro-tip">Pro Tip</a></li>
        </ul>
      </li>
      <li><a href="#disabling-unnecessary-skills" id="markdown-toc-disabling-unnecessary-skills">Disabling unnecessary skills</a></li>
      <li><a href="#limiting-short-term-memory" id="markdown-toc-limiting-short-term-memory">Limiting short-term memory</a></li>
      <li><a href="#restarting-the-container" id="markdown-toc-restarting-the-container">Restarting the container</a></li>
    </ul>
  </li>
  <li><a href="#universal-api-key" id="markdown-toc-universal-api-key">Universal API Key</a></li>
  <li><a href="#multi-model-strategy" id="markdown-toc-multi-model-strategy">Multi-Model Strategy</a>    <ul>
      <li><a href="#auto-router" id="markdown-toc-auto-router">Auto Router</a></li>
    </ul>
  </li>
  <li><a href="#openrouter-beyond-openclaw" id="markdown-toc-openrouter-beyond-openclaw">OpenRouter beyond OpenClaw</a></li>
</ul>

<h2 id="introduction">Introduction</h2>

<p>This post is a continuation of - <strong><a href="https://blog.tomaszdunia.pl/openclaw/">OpenClaw - Personal AI Assistant</a></strong>, where I described how to start your journey with <strong>OpenClaw</strong>. As a reminder, I used the <strong>free Gemini API</strong> under the <strong>Free Tier</strong> in <strong>Google AI Studio</strong> for testing. In the conclusions of that previous post, I realized that while this model is sufficient to check the general concept and see if OpenClaw works at all, it was clearly the <strong>weakest point of the environment</strong> and needed to be modified. That modification is <strong>connecting a paid API</strong> of one of the leading current models. Many people online recommend using OpenClaw with <strong>Claude Sonnet</strong> from <strong>Anthropic</strong>. Others say it’s too expensive and better to go with the slightly cheaper <strong>Gemini 3 Pro</strong> from <strong>Google</strong>. There are also other camps suggesting the <strong>superiority of more niche models due to their price-to-quality ratio</strong>. I see the following problems here:</p>
<ol>
  <li><strong>Each model is specialized in something else</strong>; model A might be better at coding, while model B is better at generating images.</li>
  <li><strong>There is no single leader</strong>; although one of the well-known models often comes out in a new version and pulls ahead of the rest, others catch up shortly after, and the chase continues—only the rabbit changes.</li>
  <li><strong>Overpaying for simple tasks</strong>—you don’t always need a high-end model. Paying for Claude Opus tokens assigned to check the weather today and determine if you need an umbrella is like hiring a lawyer to bring mail from your mailbox to your door, or using a sledgehammer to crack a nut.</li>
</ol>

<p>Do you see what I mean? <strong>There is no single solution (model) optimized for both performance and cost at the same time.</strong> It’s impossible to decide on just one model because if we go with something more advanced, we’ll pay dearly for it, and if we optimize for costs, we won’t be satisfied with the results of a “clunky” cheap model. If only there were a way to have your cake and eat it too—meaning, to have one tool that brings together many models within its service, allowing you to seamlessly switch between them depending on your current needs… 🤔</p>

<p>And this is where <strong><a href="https://openrouter.ai/">OpenRouter</a></strong> enters on a white horse. Contrary to what you might think, this material is NOT sponsored! :)</p>

<h2 id="what-is-openrouter">What is OpenRouter</h2>

<p><strong>OpenRouter</strong> is a <strong>centralized platform</strong> acting as a universal interface (API) for <strong>almost all AI language models available on the market</strong>. <strong>Instead of setting up separate developer accounts</strong> with providers like OpenAI, Google, Anthropic, or Mistral, you register in only one place and generate <strong>one universal access key</strong>. This allows you to <strong>freely switch between flagship engines</strong>—such as GPT-4o, Claude 3.7 Sonnet, or Gemini Pro—by simply swapping the model ID in the configuration of your application or assistant.</p>

<p>Billing on the platform works on a convenient <strong>prepaid model</strong> with a shared wallet. You pay a single deposit (e.g., $10), and the system deducts fractions of a cent for actually consumed tokens, <strong>regardless of which company’s services you are currently using</strong>. Crucially, this solution has no hidden financial catches. <strong>Token prices are exactly the same as when purchasing access directly from their creators</strong>, because the platform earns from its own wholesale B2B discounts, not on margins for end users.</p>

<p>Another powerful advantage of this solution is reliability and freedom from territorial barriers. OpenRouter gives instant access to the latest models, which are often <strong>initially blocked for users in Europe due to legal regulations</strong>. The platform’s unified API also fits perfectly into the configuration of fallback model chains. If a main provider’s servers fail or impose a Rate Limit, the system can redirect your command to a backup engine from another company in a fraction of a second and <strong>without interrupting your work</strong>.</p>

<h2 id="registration">Registration</h2>

<ol>
  <li>Go to <strong><a href="https://openrouter.ai/">https://openrouter.ai/</a></strong> and click the <strong>Sign Up</strong> button in the top right corner.</li>
  <li>Enter your login and password and accept the terms of service. Confirm with the <strong>Continue</strong> button.</li>
  <li>Check your email client and confirm your email.</li>
  <li>After successfully logging in, find the three horizontal lines icon in the top right corner. Hovering over it will expand a menu from which you select <strong>Settings</strong>. From the menu on the right, choose <strong>Settings -&gt; Account</strong>, then in the <strong>User</strong> row, click <strong>Manage</strong>. Go to the <strong>Security</strong> tab and in the <strong>Two-step verification</strong> row, click <strong>+ Add two-step verification</strong>. I recommend using this additional security layer before depositing any money. As always, I recommend the <strong><a href="https://github.com/ente-io/ente">Ente Auth</a></strong> app.</li>
</ol>

<h2 id="topping-up-the-account">Topping up the account</h2>

<ol>
  <li>Return to <strong>Settings</strong> and this time go to <strong><a href="https://openrouter.ai/settings/credits">Credits</a></strong>. This is where you will manage your finances.</li>
  <li>In the <strong>Buy Credits</strong> section, click the purple <strong>Add Credits</strong> button.</li>
  <li>A window will appear where you enter your <code class="language-plaintext highlighter-rouge">name and surname</code>, <code class="language-plaintext highlighter-rouge">country</code>, and <code class="language-plaintext highlighter-rouge">address</code>. Confirm with <strong>Update Address</strong>.</li>
  <li>In the <code class="language-plaintext highlighter-rouge">Add a Payment Method</code> window, start by checking <strong>Use one-time payment methods</strong> at the bottom.</li>
  <li>The window will change to <code class="language-plaintext highlighter-rouge">Purchase Credits</code>. This way, instead of adding a permanent payment method, you will only make a one-time purchase of credits. This is a much safer solution because it removes the possibility of draining your debit card or getting into debt on your credit card.</li>
  <li>Start the purchase by entering the amount you want to buy in the <strong>Amount</strong> field. This value cannot be less than 5 (or greater than 25000…). I decided to deposit $10. A tax of $0.80 will be added to this.</li>
  <li>Now you can choose the <strong>payment method</strong>. You can choose from:
    <ul>
      <li>Card,</li>
      <li>Fast bank transfer (although I couldn’t find my bank),</li>
      <li>WeChat Pay,</li>
      <li>Alipay,</li>
      <li>Cash App,</li>
      <li>Cryptocurrencies,</li>
      <li>Link,</li>
      <li>Amazon Pay.</li>
    </ul>
  </li>
  <li>I chose <strong>card</strong> and entered my virtual Revolut card details. This way, I am not only protected by doing a one-time transaction, but the virtual card is also prepaid, meaning it only has as much money as I deposit onto it beforehand.</li>
  <li>The $10 amount was immediately added to my account.</li>
</ol>

<h2 id="bot-optimization">Bot Optimization</h2>

<p>Before we connect OpenRouter to our OpenClaw agent, we should optimize it a bit. Now that <strong>real money</strong> is involved, if you <strong>don’t want to pay for nonsense</strong>, you need to change the bot’s settings to minimize those mistakes.</p>

<h3 id="editing-personality-files">Editing personality files</h3>

<p>In the <a href="https://blog.tomaszdunia.pl/openclaw/#podpowied%C5%BA">OpenClaw guide</a>, I wrote that it’s good practice to <strong>keep it to a minimum</strong> regarding the files defining the bot’s “personality.” These files are <strong>included in every request</strong> sent to the API, so <strong>the more extensive they are, the more we pay</strong>. Therefore, let’s look at them and make some changes. We can modify them in two ways:</p>
<ol>
  <li>From the terminal on the VPS by going to the folder where they are located <code class="language-plaintext highlighter-rouge">cd /home/manager/.openclaw/workspace</code> and editing them one by one using the <code class="language-plaintext highlighter-rouge">nano</code> editor.</li>
  <li>From the control panel by going to <strong>Agent -&gt; Agents -&gt; Files</strong>.</li>
</ol>

<p>Let’s go through them one by one.</p>

<h4 id="agentsmd">AGENTS.md</h4>

<p>I’m not changing the content of this file and leaving it as default. I might introduce some changes in the future, but for now, I don’t see the need. In my opinion, this is the most important file, providing general instructions for the bot’s behavior and how to use the other files listed below. Be careful when editing it, as you might unintentionally “impair” the bot.</p>

<h4 id="soulmd">SOUL.md</h4>

<p>As a reminder, this file defines how the bot should behave. The content of my <code class="language-plaintext highlighter-rouge">SOUL.md</code> file is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Direct, technical assistant.
- Respond as concisely as possible, without unnecessary fluff or greetings.
- Avoid corporate jargon and artificial politeness.
- If you are not sure about something, say "I don't know" directly instead of making things up or hallucinating.
</code></pre></div></div>

<h4 id="toolsmd">TOOLS.md</h4>

<p>I suggest leaving this file in its original form.</p>

<h4 id="identitymd">IDENTITY.md</h4>

<p>The file where we create the bot’s identity:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Nickname: Areczek
- My personal AI assistant.
- Running in Docker on a Hetzner VPS.
- Communication: Telegram.
</code></pre></div></div>

<h4 id="usermd">USER.md</h4>

<p>Here we put basic information about ourselves that we consider useful for collaborating with the bot:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Name: Tomasz
- Job: Engineer, designer, mechatronics, city bus industry.
- Hobbies: technical blog (blog.tomaszdunia.pl), self-hosting, smart home (Home Assistant), open source, sport shooting (firearms).
- Sports: Motorsports (speedway, F1).
- Socials: Mastodon - infosec.exchange/@to3k
- Location: Lublin, Poland.
</code></pre></div></div>

<h4 id="heartbeatmd">HEARTBEAT.md</h4>

<p>Clear it to zero. This is where recurring and background tasks will go, but the bot will fill this in itself. You can check here occasionally to see if it’s performing any strange tasks in the background (without your knowledge).</p>

<h4 id="bootstrapmd">BOOTSTRAP.md</h4>

<p>This file is only useful during the bot’s first run. The configuration we are doing now replaces this first step, so we clear this file so it doesn’t unnecessarily clutter our prompts.</p>

<h4 id="memorymd">MEMORY.md</h4>

<p>In my case, this file didn’t exist by default, so I created it and left it empty. This is the place where the bot itself will save things it needs to keep in long-term memory.</p>

<h4 id="pro-tip">Pro Tip</h4>

<p>The above files are used to customize the assistant to your needs. As they say, appetite comes with eating, so we will definitely want to tweak something in the future. Our requirements for the assistant will also change. A good employee can always be better. Modify these files until you achieve a satisfying result. However, remember one thing. Some LLMs cache the content of these files. An example of such a model is Claude from Anthropic. After the first reading of our assistant’s “personality” files, this model will remember them, and for the next API request, we will pay only 90% for using this part of the memory. There is one condition: the content of these files must not change. Any even minor change will cause re-caching, and thus we lose the 90% discount.</p>

<h3 id="disabling-unnecessary-skills">Disabling unnecessary skills</h3>

<p>OpenClaw starts with default skills, which in my case was as many as 50. I reviewed the entire list and concluded that I don’t need any of them, and even if I do in the future, I can quickly enable them. The instructions for all enabled skills are attached to every request sent to the API, so if we don’t use them, they are just unnecessary filler. You can check the list of skills in the control panel under <strong>Agent -&gt; Skills</strong>, and you can also disable them all from there. Clicking <code class="language-plaintext highlighter-rouge">Disable</code> 50 times isn’t convenient, so I suggest doing it from the VPS terminal. To do this, edit the file <code class="language-plaintext highlighter-rouge">/home/manager/.openclaw/openclaw.json</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /home/manager/.openclaw/openclaw.json
</code></pre></div></div>

<p>Skills are located in the <code class="language-plaintext highlighter-rouge">skills</code> section and then <code class="language-plaintext highlighter-rouge">entries</code>, and they are disabled by changing the value of the <code class="language-plaintext highlighter-rouge">enabled</code> parameter to <code class="language-plaintext highlighter-rouge">false</code>. Example of disabling the 1password skill:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"skills"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nl">"entries"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"1password"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="err">...</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="limiting-short-term-memory">Limiting short-term memory</h3>

<p>Every subsequent message we send generates another prompt call to the API (for which we pay). Each such subsequent <strong>prompt contains the history of the given chat</strong>, i.e., a number of messages from the Telegram conversation looking back. You could loosely call this the <strong>bot’s short-term memory</strong>. Obviously, <strong>the larger the block of text with history</strong> sent in each prompt, <strong>the more tokens are consumed</strong> and <strong>the more we pay</strong>. Therefore, we will set a much <strong>lower limit</strong> here than, say, the Claude Sonnet model allows, for which the <code class="language-plaintext highlighter-rouge">Context Limit</code> can be up to 200,000. Let’s set the value of this parameter <strong>4 times lower</strong>, i.e., 50,000.</p>

<p>If you’re worried that this will essentially make the assistant “stupid,” don’t worry, because <strong>OpenClaw has the <code class="language-plaintext highlighter-rouge">MEMORY.md</code> file</strong>, which is like <strong>long-term memory</strong>. Reducing the capacity of short-term memory will only mean that the bot will <strong>more frequently make summaries and save what’s important in a shortened version to the file</strong> with long-term memory.</p>

<p>This parameter is defined in the file <code class="language-plaintext highlighter-rouge">/home/manager/.openclaw/openclaw.json</code>, so let’s open it for editing:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /home/manager/.openclaw/openclaw.json
</code></pre></div></div>

<p>In its content, we need to find <code class="language-plaintext highlighter-rouge">agents</code>, then <code class="language-plaintext highlighter-rouge">defaults</code>, and finally add <code class="language-plaintext highlighter-rouge">"contextTokens": 50000</code>. Below I’m providing a fragment of the <code class="language-plaintext highlighter-rouge">openclaw.json</code> content to show how to add it:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"agents"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"defaults"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"model"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="err">...</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"models"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="err">...</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"compaction"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="err">...</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"maxConcurrent"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w">
      </span><span class="nl">"subagents"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"maxConcurrent"</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"contextTokens"</span><span class="p">:</span><span class="w"> </span><span class="mi">50000</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="err">,</span><span class="w">
</span></code></pre></div></div>

<p>Of course, save and close the file - <strong>Control (CTRL) + X</strong>, then <strong>y</strong> and <strong>ENTER</strong>.</p>

<h3 id="restarting-the-container">Restarting the container</h3>

<p>Finally, let’s restart the container to load the new configuration with all the changes described above:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker compose restart openclaw-gateway
</code></pre></div></div>

<p>I think our bot is now worthy of having money loaded into it.</p>

<h2 id="universal-api-key">Universal API Key</h2>

<p>We return to the <a href="https://openrouter.ai/">OpenRouter</a> website and finally obtain that legendary universal API key, giving access to a database of so many different models from various providers.</p>

<ol>
  <li>Go to <strong>Settings -&gt; <a href="https://openrouter.ai/settings/keys">API Keys</a></strong> and click the purple <strong>Create</strong> button.</li>
  <li>In the window that appears:
    <ul>
      <li>In the <code class="language-plaintext highlighter-rouge">Name</code> field, provide a name for our key, e.g., <strong>OpenClaw Assistant</strong>.</li>
      <li>In the <code class="language-plaintext highlighter-rouge">Credit limit (optional)</code> field, we can enter a credit limit we want to impose on this key; I entered <strong>5 dollars</strong>. If left empty, it’s unlimited (who’s going to stop the rich…).</li>
      <li>The <code class="language-plaintext highlighter-rouge">Reset limit every...</code> dropdown connects directly to the previous limit field and defines the limit reset interval; I chose <strong>Daily</strong>, because I can handle the bot eating up $5 in one day.</li>
      <li>The <code class="language-plaintext highlighter-rouge">Expiration</code> dropdown allows us to define the lifespan of this API key; I chose <strong>No expiration</strong> because I have no problem with the key being eternal since it will be useless once the entire balance is used—and remember, I chose the prepaid billing model instead of adding a card permanently.</li>
    </ul>
  </li>
  <li>Confirm with the <strong>Create</strong> button.</li>
  <li>
    <p>As a result, we will receive a message containing the key, which should be saved in a safe place:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Your new key:
 OPENROUTER_API_KEY_HERE

 Please copy it now and write it down somewhere safe. You will not be able to see it again.
 You can use it with OpenAI-compatible apps, or your own code
</code></pre></div>    </div>
  </li>
  <li>
    <p>We will now add the received key to our bot’s environment. Open the file <code class="language-plaintext highlighter-rouge">/home/manager/openclaw/.env</code> for editing:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> nano /home/manager/openclaw/.env
</code></pre></div>    </div>
  </li>
  <li>
    <p>Add a line at the end, where instead of <code class="language-plaintext highlighter-rouge">OPENROUTER_API_KEY_HERE</code> you provide the OpenRouter API key created in the previous steps:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nv">OPENROUTER_API_KEY</span><span class="o">=</span>OPENROUTER_API_KEY_HERE
</code></pre></div>    </div>
  </li>
  <li>
    <p>Open another file for editing: <code class="language-plaintext highlighter-rouge">/home/manager/openclaw/docker-compose.yml</code>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> nano /home/manager/openclaw/docker-compose.yml
</code></pre></div>    </div>
  </li>
  <li>
    <p>At the end of the <code class="language-plaintext highlighter-rouge">environment</code> section, add the line:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> - <span class="nv">OPENROUTER_API_KEY</span><span class="o">=</span><span class="k">${</span><span class="nv">OPENROUTER_API_KEY</span><span class="k">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>One last container restart:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose up <span class="nt">-d</span> openclaw-gateway
</code></pre></div>    </div>
  </li>
</ol>

<h2 id="multi-model-strategy">Multi-Model Strategy</h2>

<p>OpenRouter is an excellent service. It’s brilliant in its simplicity. It doesn’t rob its users with any additional margins, and thus has a simple earning model based on bringing together many retailers, offering them the same prices as individual producers, and earning from the fact that it actually buys in bulk—because many retailers combined are essentially a wholesaler—and thus gets better prices, which implies income based on the difference between wholesale and retail prices.</p>

<p>However, for us, besides the prices, the most important function offered by OpenRouter is the ability to juggle—i.e., seamlessly jump between individual models. Of course, you could decide on one model, e.g., Claude Sonnet, link it permanently with your OpenClaw bot, and eventually replace it in the future with some other model that comes out and proves to be more efficient. But it would be a sin not to go deeper and take advantage of the flexibility OpenRouter offers. This is where the Multi-Model strategy comes in.</p>

<p>There are many ways to approach using multiple models, but I will present only the simplest one that requires the least attention. Let’s call it the “solution for the lazy.”</p>

<h3 id="auto-router">Auto Router</h3>

<p>Whoever is behind OpenRouter has a good head on their shoulders. They came up with a mechanism that works like this:</p>
<ol>
  <li>We send a request to OpenRouter using the API key.</li>
  <li>The request goes to a small, ultra-fast meta-model run by OpenRouter, which we’ll call the “gatekeeper.”</li>
  <li>In a fraction of a second, the gatekeeper performs a basic analysis of our request for intent classification:
    <ul>
      <li><strong>Complexity Scoring</strong> - The gatekeeper scans the prompt for difficulty. If it detects a task requiring advanced reasoning (e.g., writing code, architectural analysis, math), it gives it a high weight and directs it to frontier-class models (like Claude 3.7 Sonnet or GPT-4o). If it’s a trivial task (e.g., routine bot heartbeat, translation, simple classification), it directs it to cheap models (like Llama 3 or Gemini Flash).</li>
      <li><strong>Context Windowing</strong> - The system counts tokens on the fly (length of the message and pasted logs or chat history). If you send a data packet of 50,000 tokens, the router automatically rejects models that have a smaller memory window and selects the one that can physically handle that request volume.</li>
      <li><strong>Live Telemetry (Health &amp; Latency Check)</strong> - OpenRouter constantly monitors the status of provider servers. The routing decision takes into account whether the Anthropic or OpenAI API is having a hiccup (Rate Limits) at that moment. If the main, intelligent model from one provider doesn’t respond, the router dynamically shifts the request to its counterpart at another company.</li>
    </ul>
  </li>
  <li>After classification, the <strong>Proxy and Forwarding</strong> step occurs—after making a decision, the algorithm overwrites the target model ID in the HTTP headers and sends the request through its unified API to the selected creator’s servers. The result comes back to you through the exact same channel.</li>
</ol>

<p>Sounds promising, right? It convinced me, which is why I first decided to test this variant and am doing so right now. I’ll probably update this post later with my thoughts after testing.</p>

<p>Okay, but how to configure it?</p>
<ol>
  <li>
    <p>Log in to the VPS server:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh manager@IPV4_ADDRESS
</code></pre></div>    </div>
  </li>
  <li>
    <p>Open the file <code class="language-plaintext highlighter-rouge">/home/manager/.openclaw/openclaw.json</code> in the editor:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> nano /home/manager/.openclaw/openclaw.json
</code></pre></div>    </div>
  </li>
  <li>
    <p>Modify its content to look as follows:</p>

    <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="w">
   </span><span class="nl">"meta"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"lastTouchedVersion"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026.2.20"</span><span class="p">,</span><span class="w">
     </span><span class="nl">"lastTouchedAt"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-02-24T22:48:06.665Z"</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"agents"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"defaults"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
       </span><span class="nl">"model"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"primary"</span><span class="p">:</span><span class="w"> </span><span class="s2">"openrouter/openrouter/auto"</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"heartbeat"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"every"</span><span class="p">:</span><span class="w"> </span><span class="s2">"6h"</span><span class="p">,</span><span class="w">
         </span><span class="nl">"model"</span><span class="p">:</span><span class="w"> </span><span class="s2">"openrouter/google/gemini-3-flash"</span><span class="p">,</span><span class="w">
         </span><span class="nl">"target"</span><span class="p">:</span><span class="w"> </span><span class="s2">"last"</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"compaction"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"safeguard"</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"maxConcurrent"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w">
       </span><span class="nl">"subagents"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"maxConcurrent"</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"contextTokens"</span><span class="p">:</span><span class="w"> </span><span class="mi">50000</span><span class="w">
     </span><span class="p">}</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"messages"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"ackReactionScope"</span><span class="p">:</span><span class="w"> </span><span class="s2">"group-mentions"</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"commands"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"native"</span><span class="p">:</span><span class="w"> </span><span class="s2">"auto"</span><span class="p">,</span><span class="w">
     </span><span class="nl">"nativeSkills"</span><span class="p">:</span><span class="w"> </span><span class="s2">"auto"</span><span class="p">,</span><span class="w">
     </span><span class="nl">"restart"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"channels"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"telegram"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
       </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
       </span><span class="nl">"dmPolicy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pairing"</span><span class="p">,</span><span class="w">
       </span><span class="nl">"botToken"</span><span class="p">:</span><span class="w"> </span><span class="s2">"TELEGRAM_TOKEN"</span><span class="p">,</span><span class="w">
       </span><span class="nl">"groupPolicy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"allowlist"</span><span class="p">,</span><span class="w">
       </span><span class="nl">"streamMode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"partial"</span><span class="w">
     </span><span class="p">}</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"skills"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"entries"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
       </span><span class="nl">"1password"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="err">...</span><span class="w">
       </span><span class="nl">"weather"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">}</span><span class="w">
     </span><span class="p">}</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"plugins"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"entries"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
       </span><span class="nl">"telegram"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
       </span><span class="p">}</span><span class="w">
     </span><span class="p">}</span><span class="w">
   </span><span class="p">}</span><span class="w">
 </span><span class="p">}</span><span class="w">
</span></code></pre></div>    </div>
  </li>
  <li>Let’s discuss this file line by line:
    <ul>
      <li><strong><code class="language-plaintext highlighter-rouge">meta</code></strong>: Configuration file metadata.
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">lastTouchedVersion</code></strong>: The version of the OpenClaw system that last overwrote or updated this file (2026.2.20).</li>
          <li><strong><code class="language-plaintext highlighter-rouge">lastTouchedAt</code></strong>: Exact date and time of the last modification.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">agents.defaults</code></strong>: Default settings for your assistant.
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">model</code></strong>: The bot’s main “brain.” Assigning <code class="language-plaintext highlighter-rouge">auto</code> from OpenRouter means the system itself selects the optimal model for each request.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">heartbeat</code></strong>: Proactive background operation configuration.
            <ul>
              <li><strong><code class="language-plaintext highlighter-rouge">every</code></strong>: Time interval (waking up every 6 hours).</li>
              <li><strong><code class="language-plaintext highlighter-rouge">model</code></strong>: Engine dedicated to this task (set to the fast and cheap Gemini 3 Flash).</li>
              <li><strong><code class="language-plaintext highlighter-rouge">target</code></strong>: Specifies who the bot should direct any messages generated in the background to (<code class="language-plaintext highlighter-rouge">last</code> means the last used channel/last interlocutor).</li>
            </ul>
          </li>
          <li><strong><code class="language-plaintext highlighter-rouge">compaction.mode</code></strong>: Short-term memory management mechanism. The <code class="language-plaintext highlighter-rouge">safeguard</code> mode compresses and summarizes the oldest chat messages, preventing token limit exhaustion.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">maxConcurrent</code></strong>: Maximum number of operations (e.g., simultaneous use of several tools) that the main agent can perform in parallel (4).</li>
          <li><strong><code class="language-plaintext highlighter-rouge">subagents.maxConcurrent</code></strong>: Maximum number of independent background sub-workers the agent can launch to help with complex tasks (8).</li>
          <li><strong><code class="language-plaintext highlighter-rouge">contextTokens</code></strong>: Hard limit on chat memory (50,000 tokens) sent to the API with each message.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">messages</code></strong>:
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">ackReactionScope</code></strong>: Defines situations in which the bot should confirm reading a message with a reaction (e.g., emoji). The value <code class="language-plaintext highlighter-rouge">group-mentions</code> means it will do this only when directly mentioned (@) in a group chat.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">commands</code></strong>: Configuration for handling commands entered in the chat (e.g., on Telegram using a slash <code class="language-plaintext highlighter-rouge">/</code>).
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">native</code></strong>: Automatically enables and handles basic system commands (e.g., <code class="language-plaintext highlighter-rouge">/model</code>).</li>
          <li><strong><code class="language-plaintext highlighter-rouge">nativeSkills</code></strong>: Automatically registers and handles commands coming from installed skills.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">restart</code></strong>: Allows using the <code class="language-plaintext highlighter-rouge">/restart</code> command directly from the communicator to reset the process.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">channels.telegram</code></strong>: Telegram interface configuration.
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">enabled</code></strong>: Activates communication through this channel.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">dmPolicy</code></strong>: Rules for private messages. The <code class="language-plaintext highlighter-rouge">pairing</code> mode means every new user must provide an authorization code for the bot to talk to them.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">botToken</code></strong>: Your authentication password from BotFather.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">groupPolicy</code></strong>: Rules for groups. The <code class="language-plaintext highlighter-rouge">allowlist</code> mode blocks the bot from acting in unknown group chats unless you add them to the whitelist beforehand.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">streamMode</code></strong>: Text streaming mode. The value <code class="language-plaintext highlighter-rouge">partial</code> makes long responses update in Telegram in batches, mimicking smooth “live typing” without spamming the communicator API with every single word.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">skills.entries</code></strong>: Place where manually installed additional skills from ClawHub are saved (currently empty).</li>
      <li><strong><code class="language-plaintext highlighter-rouge">plugins.entries.telegram.enabled</code></strong>: Enables the native module (engine plugin) responsible for maintaining the connection with Telegram servers.</li>
    </ul>
  </li>
  <li>As you can see, I linked <code class="language-plaintext highlighter-rouge">openrouter/openrouter/auto</code> as the main model, but additionally for <code class="language-plaintext highlighter-rouge">heartbeat</code> (background cyclic operations), I permanently assigned the <code class="language-plaintext highlighter-rouge">openrouter/google/gemini-3-flash</code> model—the fastest and cheapest model from the newest Gemini version. Theoretically, Auto Router would handle selecting the appropriate model for heartbeats, but configuring it permanently is so simple that it’s worth avoiding any risk. Also, this allows me to strictly define the interval for background actions, and I decided on 6 hours to start.</li>
  <li>
    <p>Now let’s reset the container to save the changes:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose restart openclaw-gateway
</code></pre></div>    </div>
  </li>
</ol>

<p>And how does it work in practice? Quite simply. I noticed that the entire dialogue with me on Telegram is conducted based on the Gemini 2.5 Flash model. If the agent gets a harder task, it delegates it to a subagent, which performs it on a more complex model. In my case, Claude Opus was selected, for which I unfortunately paid quite a bit, as it is one of the most expensive among the available models. I must admit, however, that I assigned the agent a rather complex task for which the instruction itself was a quite long prompt. I think I need to learn a bit more about optimization, because I’ll go bankrupt pretty quickly this way.</p>

<h2 id="openrouter-beyond-openclaw">OpenRouter beyond OpenClaw</h2>

<p>OpenRouter can also be <strong>used like a regular chat</strong>. Just go to the <strong><a href="https://openrouter.ai/chat">https://openrouter.ai/chat</a></strong> website. However, it’s not exactly a normal chat. Since OpenRouter is an LLM model aggregator, we can not only jump seamlessly between models and ask them subsequent questions alternately, but we can also ask the same question to several models at once or enable the Auto Router function, which will match the appropriate model itself to optimize costs and result quality.</p>

<p>I also recommend checking out the <strong><a href="https://openrouter.ai/rankings">Model Rankings</a></strong>, which is an invaluable source of information on which models are currently trending (most frequently used). This way, you can pick up which model is currently the most effective, but also which one is the most cost-effective due to its quality-to-price ratio.</p>

<p>Meanwhile, the <strong><a href="https://openrouter.ai/models">Model Database</a></strong> offers very extensive and detailed search filters, helping to find a model suitable for a specific application.</p>]]></content><author><name>Tomasz Dunia</name></author><category term="projects" /><category term="self-hosting-eng" /><category term="tutorials" /><category term="openrouter" /><category term="openclaw" /><category term="hetzner" /><category term="ai" /><category term="llm" /><category term="bot" /><category term="assistant" /><category term="gemini" /><category term="chatgpt" /><category term="claude" /><category term="openai" /><category term="anthropic" /><category term="google" /><category term="vps" /><category term="ssh" /><category term="telegram" /><category term="api" /><summary type="html"><![CDATA[🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/openrouter.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/openrouter.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">OpenClaw + OpenRouter</title><link href="https://blog.tomaszdunia.pl/openrouter/" rel="alternate" type="text/html" title="OpenClaw + OpenRouter" /><published>2026-02-26T00:00:00+00:00</published><updated>2026-02-26T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/openrouter</id><content type="html" xml:base="https://blog.tomaszdunia.pl/openrouter/"><![CDATA[<p><a href="https://blog.tomaszdunia.pl/openrouter-eng/">🇵🇱-&gt;🇬🇧 Go to english version of this post / Przejdź do angielskiej wersji tego wpisu</a></p>

<p>Spis treści:</p>
<ul id="markdown-toc">
  <li><a href="#wstęp" id="markdown-toc-wstęp">Wstęp</a></li>
  <li><a href="#czym-jest-openrouter" id="markdown-toc-czym-jest-openrouter">Czym jest OpenRouter</a></li>
  <li><a href="#rejestracja" id="markdown-toc-rejestracja">Rejestracja</a></li>
  <li><a href="#doładowanie-konta" id="markdown-toc-doładowanie-konta">Doładowanie konta</a></li>
  <li><a href="#optymalizacja-bota" id="markdown-toc-optymalizacja-bota">Optymalizacja bota</a>    <ul>
      <li><a href="#edycja-plików-osobowości" id="markdown-toc-edycja-plików-osobowości">Edycja plików osobowości</a>        <ul>
          <li><a href="#agentsmd" id="markdown-toc-agentsmd">AGENTS.md</a></li>
          <li><a href="#soulmd" id="markdown-toc-soulmd">SOUL.md</a></li>
          <li><a href="#toolsmd" id="markdown-toc-toolsmd">TOOLS.md</a></li>
          <li><a href="#identitymd" id="markdown-toc-identitymd">IDENTITY.md</a></li>
          <li><a href="#usermd" id="markdown-toc-usermd">USER.md</a></li>
          <li><a href="#heartbeatmd" id="markdown-toc-heartbeatmd">HEARTBEAT.md</a></li>
          <li><a href="#bootstrapmd" id="markdown-toc-bootstrapmd">BOOTSTRAP.md</a></li>
          <li><a href="#memorymd" id="markdown-toc-memorymd">MEMORY.md</a></li>
          <li><a href="#podpowiedź" id="markdown-toc-podpowiedź">Podpowiedź</a></li>
        </ul>
      </li>
      <li><a href="#wyłączenie-niepotrzebnych-skilli" id="markdown-toc-wyłączenie-niepotrzebnych-skilli">Wyłączenie niepotrzebnych skilli</a></li>
      <li><a href="#ograniczenie-pamięci-krótkotrwałej" id="markdown-toc-ograniczenie-pamięci-krótkotrwałej">Ograniczenie pamięci krótkotrwałej</a></li>
      <li><a href="#restart-kontenera" id="markdown-toc-restart-kontenera">Restart kontenera</a></li>
    </ul>
  </li>
  <li><a href="#uniwersalny-klucz-api" id="markdown-toc-uniwersalny-klucz-api">Uniwersalny klucz API</a></li>
  <li><a href="#strategia-multi-model" id="markdown-toc-strategia-multi-model">Strategia Multi-Model</a>    <ul>
      <li><a href="#auto-router" id="markdown-toc-auto-router">Auto Router</a></li>
    </ul>
  </li>
  <li><a href="#openrouter-poza-openclaw" id="markdown-toc-openrouter-poza-openclaw">OpenRouter poza OpenClaw</a></li>
</ul>

<h2 id="wstęp">Wstęp</h2>

<p>Niniejszy wpis jest kontynuacją - <strong><a href="https://blog.tomaszdunia.pl/openclaw/">OpenClaw - Personalny Asystent AI</a></strong>, w którym opisałem jak rozpocząć swoją przygodę z <strong>OpenClaw</strong>. Przypomnijmy sobie, że do testów wykorzystałem <strong>darmowe API Gemini</strong> w ramach planu <strong>Free Tier</strong> w <strong>Google AI Studio</strong>. Już w ramach wniosków z tego poprzedniego wpisu doszedłem do tego, że ten model jest wystarczający, żeby sprawdzić ogólny koncept i czy OpenClaw w ogóle działa, ale jasnym było, że jest to <strong>najsłabszy punkt środowiska</strong>, który trzeba zmodyfikować. Tą modyfikacją jest <strong>podpięcie płatnego API</strong> jednego z wiodących obecnie modeli. Wiele osób poleca w Internecie używanie OpenClaw z <strong>Claude Sonnet</strong> od <strong>Anthropic</strong>. Inni mówią, że to zbyt drogie rozwiązanie i lepiej postawić na nieco tańsze <strong>Gemini 3 Pro</strong> od <strong>Google</strong>. Są też kolejne obozy, które sugerują <strong>wyższość bardziej niszowych modeli ze względu na ich współczynnik ceny do jakości</strong>. Problemy tutaj widzę takie:</p>
<ol>
  <li><strong>każdy model jest wyspecjalizowany w czym innym</strong>, model A może być lepszy w kodowaniu, a model B w generowaniu obrazów,</li>
  <li><strong>nie ma jednego lidera</strong>, choć często jeden spośród znanych modeli wychodzi w nowej wersji i odstaje od reszty, ale za chwilę pozostali przeganiają, a gonienie króliczka trwa dalej tylko zmienia się króliczek,</li>
  <li><strong>przepłacanie za proste zadania</strong> - nie zawsze potrzebujesz tego wykoksanego modelu, bo płacenie za tokeny Claude Opus przydzielonego do sprawdzenia pogody na dziś i określenia czy potrzebujesz parasola to tak jak wynajęcie prawnika do przynoszenia Ci pod drzwi korespondencji ze skrzynki pocztowej, albo strzelanie z armaty do muchy.</li>
</ol>

<p>Czy rozumiesz o co mi chodzi? <strong>Nie ma jednego zoptymalizowanego jednocześnie wydajnościowo i kosztowo wyjścia</strong> (modelu). Nie sposób zdecydować się na jeden model, bo jeżeli postawimy na coś bardziej zaawansowanego to będziemy za to słono płacić, a jak z kolei podejdziemy do sprawy optymalizując koszty to nie będziemy zadowoleni z rezultatu pracy przygłupiego taniego modelu. Gdyby tylko dało się mieć ciastko i zjeść ciastko, to znaczy mieć jedno narzędzie skupiające w ramach swojej usługi wiele modeli pomiędzy którymi będzie można płynnie przeskakiwać w zależności od aktualnej potrzeby… 🤔</p>

<p>No i w tym momencie na białym rumaku wjeżdza <strong><a href="https://openrouter.ai/">OpenRouter</a></strong>. Wbrew temu co myślisz niniejszy materiał NIE jest sponsorowany! :)</p>

<h2 id="czym-jest-openrouter">Czym jest OpenRouter</h2>

<p><strong>OpenRouter</strong> to <strong>scentralizowana platforma</strong> pełniąca rolę uniwersalnego interfejsu (API) dla <strong>niemal wszystkich dostępnych na rynku modeli</strong> językowych sztucznej inteligencji. <strong>Zamiast zakładać osobne konta</strong> programistyczne u dostawców takich jak OpenAI, Google, Anthropic czy Mistral, rejestrujesz się tylko w jednym miejscu i generujesz <strong>jeden uniwersalny klucz dostępowy</strong>. Dzięki temu możesz <strong>swobodnie przełączać się pomiędzy flagowymi silnikami</strong> – takimi jak GPT-4o, Claude 3.7 Sonnet czy Gemini Pro – podmieniając wyłącznie ID modelu w konfiguracji swojej aplikacji lub asystenta.</p>

<p>Rozliczenia na platformie działają w wygodnym <strong>modelu pre-paid</strong> ze współdzielonym portfelem. Wpłacasz pojedynczy depozyt (np. 10 dolarów), a system na bieżąco pobiera ułamki centów za faktycznie zużyte tokeny, <strong>niezależnie od tego, z usług jakiej firmy aktualnie korzystasz</strong>. Co niezwykle istotne, rozwiązanie to nie posiada ukrytych haczyków finansowych. <strong>Ceny za tokeny są dokładnie takie same, jak przy zakupie dostępu bezpośrednio u ich twórców</strong>, ponieważ platforma zarabia na własnych, hurtowych zniżkach B2B, a nie na marżach dla użytkowników końcowych.</p>

<p>Kolejnym potężnym atutem tego rozwiązania jest niezawodność oraz wolność od barier terytorialnych. OpenRouter daje natychmiastowy dostęp do najnowszych modeli, które często <strong>z powodu regulacji prawnych są początkowo blokowane dla użytkowników z Europy</strong>. Ujednolicone API platformy idealnie wpisuje się również w konfigurację łańcuchów modeli zapasowych (Fallbacks). Jeśli serwery głównego dostawcy ulegną awarii lub narzucą limit zapytań (Rate Limit), system może w ułamku sekundy i <strong>bez przerywania pracy przekierować Twoje polecenie do zapasowego silnika</strong> od innej firmy.</p>

<h2 id="rejestracja">Rejestracja</h2>

<ol>
  <li>Wejdź na stronę <strong><a href="https://openrouter.ai/">https://openrouter.ai/</a></strong> i naciśnij przycisk <strong>Sign Up</strong> znajdujący się w prawym górnym rogu.</li>
  <li>Podaj login oraz hasło i zaakceptuj regulamin. Potwierdź przyciskiem <strong>Continue</strong>.</li>
  <li>Przejdź do swojego klienta pocztowego i odbierz maila potwierdzającego.</li>
  <li>Po udanym zalogowaniu się znajdź ikonę trzech poziomych kresek w prawym górnym rogu strony. Najechanie na nią rozwinie menu, z którego wybieramy <strong>Settings</strong>. Z menu po prawej wybieramy <strong>Settings -&gt; Account</strong>, następnie w wierszu <strong>User</strong> naciskamy przycisk <strong>Manage</strong>. Przechodzimy do zakładki <strong>Security</strong> i w wierszu <strong>Two-step verification</strong> naciskamy <strong>+ Add two-step verification</strong>. Polecam skorzystać z tej dodatkowej warstwy zabezpieczającej konto jeszcze, zanim wpłacimy na nie jakiekolwiek pieniądze. Polecam do tego jak zawsze aplikację <strong><a href="https://github.com/ente-io/ente">Ente Auth</a></strong>.</li>
</ol>

<h2 id="doładowanie-konta">Doładowanie konta</h2>

<ol>
  <li>Wracamy do <strong>Settings</strong> i tym razem przechodzimy do <strong><a href="https://openrouter.ai/settings/credits">Credits</a></strong>. To tutaj będziemy zarządzać swoimi finansami.</li>
  <li>W sekcji <strong>Buy Credits</strong> naciskamy fioletowy przycisk <strong>Add Credits</strong>.</li>
  <li>Wyskoczy okienko w którym podajemy swoje <code class="language-plaintext highlighter-rouge">imię i nazwisko</code>, <code class="language-plaintext highlighter-rouge">kraj</code> i <code class="language-plaintext highlighter-rouge">adres</code>. Potwierdzamy przyciskiem <strong>Update Address</strong>.</li>
  <li>W oknie <code class="language-plaintext highlighter-rouge">Add a Payment Method</code> zacznij od zaznaczenia na dole <strong>Use one-time payment methods</strong>.</li>
  <li>Okno zmieni się w <code class="language-plaintext highlighter-rouge">Purchase Credits</code>. W ten sposób zamiast dodawać metodę płatności na stałe dokonamy tylko jednorazowego zakupu kredytów. To znacznie bezpieczniejsze rozwiązanie, bo usuwa możliwość wyczyszczenia sobie karty debetowej lub zadłużenia się na karcie kredytowej po uszy.</li>
  <li>Zakup zaczynamy od wpisania w pole <strong>Amount</strong> kwoty za jaką chcemy dokonać zakupu. Wartość ta nie może być mniejsza niż 5 (oraz większa od 25000…). Ja postanowiłem wpłacić $10. Do tego doliczone będzie $0,80 podatku.</li>
  <li>Teraz możemy juz wybrać <strong>metodę płatności</strong>. Do wyboru mamy:
    <ul>
      <li>kartę,</li>
      <li>szybki przelew bankowy (aczkolwiek mi nie udało się znaleźć mojego banku),</li>
      <li>WeChat Pay,</li>
      <li>Alipay,</li>
      <li>Cash App,</li>
      <li>kryptowaluty,</li>
      <li>Link</li>
      <li>Amazon Pay.</li>
    </ul>
  </li>
  <li>Ja wybrałem <strong>kartę</strong> i wprowadziłem dane mojej wirtualnej karty w Revolut. W ten sposób nie dość, że jestem zabezpieczony robiąc tylko jednorazową transakcję to jeszcze wirtualna karta jest przedpłacona, czyli posiada tyle pieniędzy, ile na nią wcześniej wpłacę.</li>
  <li>Kwota $10 została natychmiast dodana do mojego konta.</li>
</ol>

<h2 id="optymalizacja-bota">Optymalizacja bota</h2>

<p>Zanim podepniemy OpenRouter do naszego agenta OpenClaw powinniśmy trochę go zoptymalizować. Teraz w grę wchodzą już <strong>realne pieniądze</strong>, więc jeżeli <strong>nie chcesz płacić za głupoty</strong> to trzeba pozmieniać ustawienia bota tak, aby jak najmniej tych głupot robił.</p>

<h3 id="edycja-plików-osobowości">Edycja plików osobowości</h3>

<p>W <a href="https://blog.tomaszdunia.pl/openclaw/#podpowied%C5%BA">poradniku o OpenClaw</a> pisałem, że dobrą praktyką jest <strong>ograniczyć się do minimum</strong> w zakresie plików definiujących “osobowość” bota. Te pliki <strong>trafiają do każdego zapytania</strong> wysłanego do API, więc <strong>im bardziej obszerne są tym więcej zapłacimy</strong>. Dlatego zajrzyjmy do nich i wprowadzmy zmiany. Modyfikować je możemy na dwa sposoby:</p>
<ol>
  <li>z poziomu terminala na serwerze VPS wchodząc do folderu, w którym się znajdują <code class="language-plaintext highlighter-rouge">cd /home/manager/.openclaw/workspace</code> i edytując za pomocą edytora <code class="language-plaintext highlighter-rouge">nano</code> wszystkie z nich po kolei,</li>
  <li>z poziomu panelu sterowania wchodząc do <strong>Agent -&gt; Agents -&gt; Files</strong>.</li>
</ol>

<p>Przejdzmy przez wszystkie z nich po kolei.</p>

<h4 id="agentsmd">AGENTS.md</h4>

<p>Treści tego pliku nie zmieniam i zostawiam domyślną. Możliwe, że w przyszłości wprowadzę tam jakieś zmiany, ale na razie nie widzę takiej potrzeby. W mojej ocenie jest to najważniejszy plik, który stanowi ogólną instrukcję zachowania bota oraz to jak korzystać z pozostałych plików, które wymienię poniżej. Edytując go trzeba uważać, bo można tym niechcący upośledzić bota.</p>

<h4 id="soulmd">SOUL.md</h4>

<p>Przypomnę, że jest to plik, który określa jaki bot ma się zachowywać. Treść mojego pliku <code class="language-plaintext highlighter-rouge">SOUL.md</code> to:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Bezpośredni, techniczny asystent.
- Odpowiadaj maksymalnie konkretnie, bez zbędnej otoczki i powitań
- Unikaj korporacyjnego żargonu i sztucznej uprzejmości
- Jeżeli nie masz pewności co do tego co mówisz powiedz wprost "nie wiem" zamiast zmyślać lub halucynować.
</code></pre></div></div>

<h4 id="toolsmd">TOOLS.md</h4>

<p>Proponuję zostawić ten plik w pierwotnej formie.</p>

<h4 id="identitymd">IDENTITY.md</h4>

<p>Plik, w którym tworzymy tożsamość bota:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Pseudonim: Areczek
- Mój osobisty asystent AI
- Uruchomiony w Docker na VPS od Hetzner
- Komunikacja: Telegram
</code></pre></div></div>

<h4 id="usermd">USER.md</h4>

<p>Tu wrzucamy podstawowe informacje o sobie, które uznamy za użyteczne w kontekście współpracy z botem:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Imię: Tomasz
- Praca: Inżynier, konstruktor, mechatronik, branża autobusy miejskie
- Hobby: blog techniczny (blog.tomaszdunia.pl), self-hosting, smarthome (Home Assistant), open source, strzelectwo sportowe (broń palna)
- Sport: motorowe (żużel, F1)
- Sociale: Mastodon - infosec.exchange/@to3k
- Mieszka: Lublin, Polska
</code></pre></div></div>

<h4 id="heartbeatmd">HEARTBEAT.md</h4>

<p>Czyścimy do zera. Tutaj będą trafiać zadania cykliczne i związane z pracą w tle, ale to bot będzie sobie wypełniał sam. Można tutaj ewentualnie zajrzeć co jakiś czas, żeby sprawdzić czy wykonuje w tle (bez naszej wiedzy) jakiś dziwnych tasków.</p>

<h4 id="bootstrapmd">BOOTSTRAP.md</h4>

<p>Ten plik przydaje się tylko przy pierwszym uruchomieniu bota. Konfiguracja, którą wykonujemy teraz zastępuje ten pierwszy krok, więc czyścimy ten plik, żeby nam nie zawalał niepotrzebnie promptów.</p>

<h4 id="memorymd">MEMORY.md</h4>

<p>U mnie ten plik domyślnie w ogóle nie istniał, dlatego go utworzyłem i pozostawiłem pustym. To miejsce, gdzie bot sam będzie zapisywał rzeczy, które musi zachować w ramach pamięci długotrwałej.</p>

<h4 id="podpowiedź">Podpowiedź</h4>

<p>Powyższe pliki służą do tego, aby za ich pomocą dostosować asystenta do swoich potrzeb. Jak to mówią apetyt rośnie w miarę jedzenia, więc na pewno będziemy chcieli w przyszłości coś podkręcić. Na pewno bedą zmieniać się także nasze wymagania względem asystenta. Dobry pracownik zawsze może być lepszy. Modyfikuj te pliki aż osiągniesz zadowalający Cię efekt. Jednakże pamiętaj o jednym. Niektóre modele LLM cache’ują (zapamiętują) zawartość tych plików. Przykładem takiego modelu jest właśnie Claude od Anthropic. Po pierwszym zapoznaniu się z plikami “osobowości” naszego asystenta model ten zapamięta je i przy następnym zapytaniu API zapłacimy tylko 90% za skorzystanie z tej części pamięci. Jest jednak jeden warunek. Zawartość tych plików nie może uleć zmianie. Każda nawet drobna zmiana spowoduje ponowne cachowanie i tym samym przepada nam zniżka 90%.</p>

<h3 id="wyłączenie-niepotrzebnych-skilli">Wyłączenie niepotrzebnych skilli</h3>

<p>OpenClaw uruchamia się z domyślnymi skillami, których w moim przypadku było aż 50. Przejrzałem całą tę listę i doszedłem do wniosku, że nie potrzebuję żadnego z nich, a nawet jeżeli będę potrzebował w przyszłości to mogę go szybko włączyć. Instrukcje obsługi wszystkich włączonych skilli są doklejane do każdego zapytania kierowanego do API, więc jeżeli nie korzystamy z nich to są tylko zbędnym zapychaczem. Listę skilli można sprawdzić w panelu sterowania w <strong>Agent -&gt; Skills</strong> i z tego poziomu można je też wszystkie wyłączyć. Kliknięcie 50 razy przycisku <code class="language-plaintext highlighter-rouge">Disable</code> nie jest wygodne, więc proponuję to zrobić z poziomu terminala serwera VPS. W tym celu edytujemy plik <code class="language-plaintext highlighter-rouge">/home/manager/.openclaw/openclaw.json</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /home/manager/.openclaw/openclaw.json
</code></pre></div></div>

<p>Skille znajdują się w sekcji <code class="language-plaintext highlighter-rouge">skills</code> i dalej <code class="language-plaintext highlighter-rouge">entries</code>, a wyłącza się je poprzez zmianę wartości parametru<code class="language-plaintext highlighter-rouge">enabled</code> na <code class="language-plaintext highlighter-rouge">false</code>. Przykład wyłaczenia skilla 1password:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"skills"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nl">"entries"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"1password"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="err">...</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="ograniczenie-pamięci-krótkotrwałej">Ograniczenie pamięci krótkotrwałej</h3>

<p>Każda kolejna wiadomość wysłana przez nas generuje wywołanie kolejnego prompta do API (za które płacimy). Każdy taki kolejny <strong>prompt zawiera historię danego czatu</strong>, tj. ileś wiadomości z konwersacji na Telegramie patrząc wstecz. Z przymrużeniem oka można to nazwać <strong>pamięcią krótkotrwałą bota</strong>. Oczywistym jest, że <strong>im większy blok tekstu z historią</strong> wysyłany jest w każdym z promptów tym <strong>więcej zużywanych jest tokenów</strong> i tym <strong>więcej płacimy</strong>. Dlatego wprowadzimy tutaj znacznie <strong>niższy limit</strong> niż pozwala na to załóżmy model Claude Sonnet, dla którego wartość <code class="language-plaintext highlighter-rouge">Context Limit</code> może maksymalnie wynosić nawet 200 000. Ustawmy <strong>4 razy mniejszą</strong> wartość tego parametru, czyli 50 000.</p>

<p>Jeżeli martwisz się, że zasadniczo ogłupi to asystenta to nie przejmuj się, bo <strong>OpenClaw ma przecież plik <code class="language-plaintext highlighter-rouge">MEMORY.md</code></strong>, który jest czymś w rodzaju <strong>pamięci długotrwałej</strong>. Zmniejszenie pojemności pamięci krótkotrwałej będzie powodowało tylko to, że bot będzie <strong>częściej robił podsumowania i w skróconej wersji zapisywał to co jest istotne do pliku</strong> z pamięcią długotrwałą.</p>

<p>Parametr ten definiuje się w pliku <code class="language-plaintext highlighter-rouge">/home/manager/.openclaw/openclaw.json</code>, zatem otwórzmy go do edycji:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /home/manager/.openclaw/openclaw.json
</code></pre></div></div>

<p>W jego treści musimy znaleźć <code class="language-plaintext highlighter-rouge">agents</code> dalej <code class="language-plaintext highlighter-rouge">defaults</code> i na końcu dodajemy <code class="language-plaintext highlighter-rouge">"contextTokens": 50000</code>. Poniżej wrzucam fragment treści <code class="language-plaintext highlighter-rouge">openclaw.json</code>, żeby pokazać jak należy to dopisać:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"agents"</span>: <span class="o">{</span>
    <span class="s2">"defaults"</span>: <span class="o">{</span>
      <span class="s2">"model"</span>: <span class="o">{</span>
        ...
      <span class="o">}</span>,
      <span class="s2">"models"</span>: <span class="o">{</span>
        ...
      <span class="o">}</span>,
      <span class="s2">"compaction"</span>: <span class="o">{</span>
        ...
      <span class="o">}</span>,
      <span class="s2">"maxConcurrent"</span>: 4,
      <span class="s2">"subagents"</span>: <span class="o">{</span>
        <span class="s2">"maxConcurrent"</span>: 8
      <span class="o">}</span>,
      <span class="s2">"contextTokens"</span>: 50000
    <span class="o">}</span>
  <span class="o">}</span>,
</code></pre></div></div>

<p>Plik oczywiście zapisujemy i zamykamy - <strong>Control (CTRL) + X</strong>, potem <strong>y</strong> i <strong>ENTER</strong>.</p>

<h3 id="restart-kontenera">Restart kontenera</h3>

<p>Na koniec zrestartujmy kontener aby załadować nową konfigurację ze wszystkimi wyżej opisanymi zmianami:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker compose restart openclaw-gateway
</code></pre></div></div>

<p>Wydaje mi się, że teraz nasz bot jest godzien ładowania w niego pieniędzy. Nie jest wykluczone, że</p>

<h2 id="uniwersalny-klucz-api">Uniwersalny klucz API</h2>

<p>Wracamy na stronę <a href="https://openrouter.ai/">OpenRouter</a> i pozyskamy w końcu ten legendarny uniwersalny klucz API, dający dostęp do bazy tak wielu różnych modeli od różnych dostawców.</p>

<ol>
  <li>Wejdź do <strong>Settings -&gt; <a href="https://openrouter.ai/settings/keys">API Keys</a></strong> i naciśnij fioletowy przycisk <strong>Create</strong>.</li>
  <li>W okienku, które wyskoczy:
    <ul>
      <li>w polu <code class="language-plaintext highlighter-rouge">Name</code> podajemy nazwę naszego klucza, np. <strong>OpenClaw Assistant</strong>,</li>
      <li>w polu <code class="language-plaintext highlighter-rouge">Credit limit (optional)</code> możemy podać limit kredytów, jaki chcemy nałożyć na ten klucz, ja wpisałem <strong>5 dolarów</strong>, jeżeli zostawimy puste to lecimy bez limitu (kto bogatemu zabroni…),</li>
      <li>lista rozwijana <code class="language-plaintext highlighter-rouge">Reset limit every...</code> łączy się bezpośrednio z poprzednim polem dotyczącym limitów i określa jaki ma być interwał resetowania limitu, ja wybrałem <strong>Daily</strong>, czyli codziennie, bo jestem w stanie przeboleć jak bot zeżre mi $5 w jeden dzień,</li>
      <li>lista rozwijana <code class="language-plaintext highlighter-rouge">Expiration</code> pozwala nam określić długość życia tego klucza API, tj. kiedy ma on wygasnąć, ja wybrałem opcję <strong>No expiration</strong>, bo nie mam problemu z tym, że klucz będzie wieczny, gdyż będzie on bezużyteczny, gdy wykorzystane zostanie całe saldo, a przypominam, że zdecydowałem się na model rozliczenia pre-paid zamiast dodawać kartę na sztywno.</li>
    </ul>
  </li>
  <li>Potwierdzamy przyciskiem <strong>Create</strong>.</li>
  <li>
    <p>W rezultacie otrzymamy komunikat, w którego treści będzie klucz, który należy zapisać w bezpiecznym miejscu:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Your new key:
 KLUCZ_API_OPENROUTER

 Please copy it now and write it down somewhere safe. You will not be able to see it again.
 You can use it with OpenAI-compatible apps, or your own code
</code></pre></div>    </div>
  </li>
  <li>
    <p>Otrzymany klucz dodamy teraz do środowiska naszego bota. Otwieramy do edycji plik <code class="language-plaintext highlighter-rouge">/home/manager/openclaw/.env</code>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> nano /home/manager/openclaw/.env
</code></pre></div>    </div>
  </li>
  <li>
    <p>Dodajemy na jego końcu linijkę, w której zamiast <code class="language-plaintext highlighter-rouge">KLUCZ_API_OPENROUTER</code> podajemy klucz API od OpenRouter, który utworzyliśmy w poprzednich krokach:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nv">OPENROUTER_API_KEY</span><span class="o">=</span>KLUCZ_API_OPENROUTER
</code></pre></div>    </div>
  </li>
  <li>
    <p>Otwieramy do edycji kolejny plik <code class="language-plaintext highlighter-rouge">/home/manager/openclaw/docker-compose.yml</code>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> nano /home/manager/openclaw/docker-compose.yml
</code></pre></div>    </div>
  </li>
  <li>
    <p>Na końcu sekcji <code class="language-plaintext highlighter-rouge">environment</code> dodajemy linijkę:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> - <span class="nv">OPENROUTER_API_KEY</span><span class="o">=</span><span class="k">${</span><span class="nv">OPENROUTER_API_KEY</span><span class="k">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>Jeszcze tylko restart kontenera:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose up <span class="nt">-d</span> openclaw-gateway
</code></pre></div>    </div>
  </li>
</ol>

<h2 id="strategia-multi-model">Strategia Multi-Model</h2>

<p>OpenRouter to wyborna usługa. Jest genialna w swojej prostocie. Nie okrada swoich użytkowników żadnymi dodatkowymi marżami, a tym samym ma prosty model zarabiania, który poleca na tym, że skupia wielu detalistów, oferuje im te same ceny co poszczególnie producenci, a zarabia na tym, że tak naprawdę kupuje hurtowo, bo wielu detalistów to tak naprawdę już hurtownik, i dzięki temu ma lepsze ceny, co implikuje dochód na bazie różnicy ceny hurtowej i detalicznej.</p>

<p>Jednakże dla nas poza cenami najważniejszą funkcją oferowaną przez OpenRouter jest możliwość żonglowania, tj. płynnego przeskakiwania pomiędzy poszczególnymi modelami. Oczywiście można by było zdecydować się na jeden model np. Claude Sonnet, spiąć go na sztywno ze swoim botem OpenClaw i ewentualnie zastąpić w przyszłości jakimś innym modelem, który wyjdzie i okaże się bardziej wydajny. Lecz byłoby grzech nie wejść bardziej w temat i nie skorzystać z tej elastyczności, którą daje OpenRouter. W tym momencie wchodzi strategia Multi-Model.</p>

<p>Do używania wielu modeli można podejść na wiele sposobów, ale ja przedstawię tylko tą najprostszą i wymagającą najmniej uwagi. Nazwijmy to rozwiązaniem dla leniwych.</p>

<h3 id="auto-router">Auto Router</h3>

<p>Ktoś kto stoi za OpenRouter ma łeb na karku. Wymyślił mechanizm działający tak:</p>
<ol>
  <li>wysyłamy zapytanie do OpenRouter używając klucza API,</li>
  <li>zapytanie trafia do małego, ultraszybkiego meta-modelu uruchomionego przez OpenRouter, którego nazwiemy dalej bramkarzem,</li>
  <li>bramkarz w ułamku sekundy robi podstawową analizę naszego zapytania, której celem jest klasyfikacja intencji (intent classification):
    <ul>
      <li><strong>Ocena Złożoności (Complexity Scoring)</strong> - bramkarz skanuje prompt pod kątem trudności. Jeżeli wykryje zadanie wymagające zaawansowanego rozumowania (np. pisanie kodu, analiza architektoniczna, matematyka), nadaje mu wysoką wagę i kieruje do modeli klasy frontier (jak Claude 3.7 Sonnet czy GPT-4o). Jeśli to błahe zadanie (np. rutynowy heartbeat bota, tłumaczenie, prosta klasyfikacja), kieruje je do modeli tanich (jak Llama 3 czy Gemini Flash).</li>
      <li><strong>Filtrowanie Kontekstu</strong> (Context Windowing) - system w locie zlicza tokeny (długość wiadomości i wklejonych logów czy historii czatu). Jeśli przesyłasz paczkę danych o wielkości 50 000 tokenów, router automatycznie odrzuca modele, które mają mniejsze okno pamięci, i wybiera ten, który fizycznie poradzi sobie z tą objętością zapytania.</li>
      <li><strong>Telemetria na żywo</strong> (Health &amp; Latency Check) - OpenRouter stale monitoruje status serwerów dostawców. Decyzja o routingu uwzględnia to, czy API Anthropic lub OpenAI nie ma w danej sekundzie czkawki (Rate Limits). Jeśli główny, inteligentny model od jednego dostawcy nie odpowiada, router dynamicznie przerzuca żądanie do jego odpowiednika u innej firmy.</li>
    </ul>
  </li>
  <li>po dokonaniu klasyfikacji następuje krok <strong>Proxy i Przekazanie</strong> (Forwarding), czyli po podjęciu decyzji algorytm nadpisuje docelowe ID modelu w nagłówkach HTTP i wysyła zapytanie przez swoje zunifikowane API do serwerów wybranego twórcy. Wynik wraca do Ciebie dokładnie tym samym kanałem.</li>
</ol>

<p>Brzmi obiecująco, prawda? Mnie to przekonuje dlatego w pierwszej kolejności zdecydowałem się na przetestowanie tego wariantu i robię to właśnie teraz. Pewnie po jakimś czasie zaktualizuję ten wpis o moje przemyślenia po testach.</p>

<p>Dobra, ale jak to skonfigurować?</p>
<ol>
  <li>
    <p>Logujemy się na serwer VPS:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh manager@ADRES_IPV4
</code></pre></div>    </div>
  </li>
  <li>
    <p>Otwieramy plik <code class="language-plaintext highlighter-rouge">/home/manager/.openclaw/openclaw.json</code> w edytorze:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> nano /home/manager/.openclaw/openclaw.json
</code></pre></div>    </div>
  </li>
  <li>
    <p>Jego treść modyfikujemy tak, aby wyglądała następująco:</p>

    <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="w">
   </span><span class="nl">"meta"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"lastTouchedVersion"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026.2.20"</span><span class="p">,</span><span class="w">
     </span><span class="nl">"lastTouchedAt"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-02-24T22:48:06.665Z"</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"agents"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"defaults"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
       </span><span class="nl">"model"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"primary"</span><span class="p">:</span><span class="w"> </span><span class="s2">"openrouter/openrouter/auto"</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"heartbeat"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"every"</span><span class="p">:</span><span class="w"> </span><span class="s2">"6h"</span><span class="p">,</span><span class="w">
         </span><span class="nl">"model"</span><span class="p">:</span><span class="w"> </span><span class="s2">"openrouter/google/gemini-3-flash"</span><span class="p">,</span><span class="w">
         </span><span class="nl">"target"</span><span class="p">:</span><span class="w"> </span><span class="s2">"last"</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"compaction"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"safeguard"</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"maxConcurrent"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w">
       </span><span class="nl">"subagents"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"maxConcurrent"</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"contextTokens"</span><span class="p">:</span><span class="w"> </span><span class="mi">50000</span><span class="w">
     </span><span class="p">}</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"messages"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"ackReactionScope"</span><span class="p">:</span><span class="w"> </span><span class="s2">"group-mentions"</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"commands"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"native"</span><span class="p">:</span><span class="w"> </span><span class="s2">"auto"</span><span class="p">,</span><span class="w">
     </span><span class="nl">"nativeSkills"</span><span class="p">:</span><span class="w"> </span><span class="s2">"auto"</span><span class="p">,</span><span class="w">
     </span><span class="nl">"restart"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"channels"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"telegram"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
       </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
       </span><span class="nl">"dmPolicy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pairing"</span><span class="p">,</span><span class="w">
       </span><span class="nl">"botToken"</span><span class="p">:</span><span class="w"> </span><span class="s2">"TOKEN_TELEGRAM"</span><span class="p">,</span><span class="w">
       </span><span class="nl">"groupPolicy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"allowlist"</span><span class="p">,</span><span class="w">
       </span><span class="nl">"streamMode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"partial"</span><span class="w">
     </span><span class="p">}</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"skills"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"entries"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
       </span><span class="nl">"1password"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"apple-notes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"apple-reminders"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"bear-notes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"blogwatcher"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"blucli"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"bluebubbles"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"camsnap"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"clawhub"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"coding-agent"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"discord"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"eightctl"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"gemini"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"gh-issues"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"gifgrep"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"github"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"gog"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"goplaces"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"healthcheck"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"himalaya"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"imsg"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"mcporter"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"model-usage"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"nano-banana-pro"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"nano-pdf"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"notion"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"openai-image-gen"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"openai-whisper"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"openai-whisper-api"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"oracle"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"openhue"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"obsidian"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"ordercli"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"peekaboo"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"sag"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"session-logs"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"sherpa-onnx-tts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"skill-creator"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"slack"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"songsee"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"sonoscli"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"spotify-player"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"summarize"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"things-mac"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"tmux"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"trello"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"video-frames"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">}</span><span class="w">
       </span><span class="nl">"voice-call"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"wacli"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">},</span><span class="w">
       </span><span class="nl">"weather"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
       </span><span class="p">}</span><span class="w">
     </span><span class="p">}</span><span class="w">
   </span><span class="p">},</span><span class="w">
   </span><span class="nl">"plugins"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
     </span><span class="nl">"entries"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
       </span><span class="nl">"telegram"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
         </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
       </span><span class="p">}</span><span class="w">
     </span><span class="p">}</span><span class="w">
   </span><span class="p">}</span><span class="w">
 </span><span class="p">}</span><span class="w">
</span></code></pre></div>    </div>
  </li>
  <li>Omówmy ten plik linijka po linijce:
    <ul>
      <li><strong><code class="language-plaintext highlighter-rouge">meta</code></strong>: Metadane pliku konfiguracyjnego.
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">lastTouchedVersion</code></strong>: Wersja systemu OpenClaw, która jako ostatnia nadpisała lub zaktualizowała ten plik (2026.2.20).</li>
          <li><strong><code class="language-plaintext highlighter-rouge">lastTouchedAt</code></strong>: Dokładna data i czas ostatniej modyfikacji.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">agents.defaults</code></strong>: Domyślne ustawienia dla Twojego asystenta.
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">model</code></strong>: Główny “mózg” bota. Przypisany <code class="language-plaintext highlighter-rouge">auto</code> z OpenRoutera oznacza, że system sam dobiera optymalny model do każdego zapytania.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">heartbeat</code></strong>: Konfiguracja proaktywnego działania w tle.
            <ul>
              <li><strong><code class="language-plaintext highlighter-rouge">every</code></strong>: Interwał czasowy (wybudzanie co 6 godzin).</li>
              <li><strong><code class="language-plaintext highlighter-rouge">model</code></strong>: Silnik dedykowany do tego zadania (ustawiony szybki i tani Gemini 3 Flash).</li>
              <li><strong><code class="language-plaintext highlighter-rouge">target</code></strong>: Określa, do kogo bot ma skierować ewentualną wiadomość wygenerowaną w tle (<code class="language-plaintext highlighter-rouge">last</code> oznacza ostatnio używany kanał/ostatniego rozmówcę).</li>
            </ul>
          </li>
          <li><strong><code class="language-plaintext highlighter-rouge">compaction.mode</code></strong>: Mechanizm zarządzania pamięcią krótkotrwałą. Tryb <code class="language-plaintext highlighter-rouge">safeguard</code> kompresuje i streszcza najstarsze wiadomości z czatu, zapobiegając przekroczeniu limitu tokenów.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">maxConcurrent</code></strong>: Maksymalna liczba operacji (np. jednoczesne użycie kilku narzędzi), które główny agent może wykonywać równolegle (4).</li>
          <li><strong><code class="language-plaintext highlighter-rouge">subagents.maxConcurrent</code></strong>: Maksymalna liczba niezależnych podwykonawców pracujących w tle, których agent może uruchomić do pomocy przy złożonych zadaniach (8).</li>
          <li><strong><code class="language-plaintext highlighter-rouge">contextTokens</code></strong>: Twardy limit pamięci czatu (50 000 tokenów) wysyłanej do API przy każdej wiadomości.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">messages</code></strong>:
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">ackReactionScope</code></strong>: Określa, w jakich sytuacjach bot ma potwierdzać przeczytanie wiadomości za pomocą reakcji (np. emoji). Wartość <code class="language-plaintext highlighter-rouge">group-mentions</code> oznacza, że zrobi to wyłącznie, gdy zostanie bezpośrednio oznaczony (@) w czacie grupowym.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">commands</code></strong>: Konfiguracja obsługi komend wpisywanych na czacie (np. na Telegramie z użyciem ukośnika <code class="language-plaintext highlighter-rouge">/</code>).
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">native</code></strong>: Automatycznie włącza i obsługuje podstawowe komendy systemowe (np. <code class="language-plaintext highlighter-rouge">/model</code>).</li>
          <li><strong><code class="language-plaintext highlighter-rouge">nativeSkills</code></strong>: Automatycznie rejestruje i obsługuje komendy pochodzące od zainstalowanych skilli.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">restart</code></strong>: Zezwala na użycie komendy <code class="language-plaintext highlighter-rouge">/restart</code> bezpośrednio z poziomu komunikatora w celu zresetowania procesu.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">channels.telegram</code></strong>: Konfiguracja interfejsu Telegram.
        <ul>
          <li><strong><code class="language-plaintext highlighter-rouge">enabled</code></strong>: Aktywuje komunikację przez ten kanał.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">dmPolicy</code></strong>: Zasady dla wiadomości prywatnych. Tryb <code class="language-plaintext highlighter-rouge">pairing</code> oznacza, że każdy nowy użytkownik musi podać kod autoryzacyjny, aby bot z nim porozmawiał.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">botToken</code></strong>: Twoje hasło uwierzytelniające z BotFathera.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">groupPolicy</code></strong>: Zasady dla grup. Tryb <code class="language-plaintext highlighter-rouge">allowlist</code> blokuje bota przed działaniem w nieznanych czatach grupowych, chyba że dodasz je wcześniej do białej listy.</li>
          <li><strong><code class="language-plaintext highlighter-rouge">streamMode</code></strong>: Tryb strumieniowania tekstu. Wartość <code class="language-plaintext highlighter-rouge">partial</code> sprawia, że długie odpowiedzi są aktualizowane w Telegramie partiami, co imituje płynne “pisanie na żywo” bez spamowania API komunikatora przy każdym pojedynczym słowie.</li>
        </ul>
      </li>
      <li><strong><code class="language-plaintext highlighter-rouge">skills.entries</code></strong>: Miejsce, w którym zapisywane są ręcznie zainstalowane umiejętności dodatkowe z ClawHub (aktualnie puste).</li>
      <li><strong><code class="language-plaintext highlighter-rouge">plugins.entries.telegram.enabled</code></strong>: Włącza rdzenny moduł (wtyczkę silnika) odpowiedzialny za utrzymanie połączenia z serwerami Telegrama.</li>
    </ul>
  </li>
  <li>Jak widzisz jako model główny podpiąłem tutaj <code class="language-plaintext highlighter-rouge">openrouter/openrouter/auto</code>, ale dodatkowo dla <code class="language-plaintext highlighter-rouge">heartbeat</code>, czyli operacji cyklicznych w tle przypisałem na sztywno model <code class="language-plaintext highlighter-rouge">openrouter/google/gemini-3-flash</code>, czyli czyli najszybszy i najtańszy model, ale z najnowszej wersji Gemini. Teoretycznie Auto Router poradził by sobie z doborem odpowiedniego modelu dla heartbeatsów, ale skonfigurowanie tego na sztywno jest tak proste, że szkoda kusić losu. Do tego taki zapis pozwala mi na sztywno określić interwał odpalania działań w tle i na początek zdecydowałem, że będzie to 6 godzin.</li>
  <li>
    <p>Teraz zresetujmy kontener, aby utrwalić zmiany:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose restart openclaw-gateway
</code></pre></div>    </div>
  </li>
</ol>

<p>A jak to działa w praktyce? Dość prosto. Zauważyłem, że cały dialog ze mną na Telegramie prowadzony jest na bazie modelu Gemini 2.5 Flash. Jeżeli agent dostanie trudniejsze zadanie to zleca je subagentowi, który wykonuje je na bardziej złożonym modelu. W moim przypadku został wytypowany Claude Opus, za którego niestety zapłaciłem dość słono, bo jest to jeden z najdroższych spośród dostępnych modeli. Trzeba jednak przyznać, że zleciłem agentowi dość złożone zadanie, do którego sama instrukcja była dość długim promptem. Muszę się chyba trochę poduczyć z optymalizacji, bo w taki sposób dość szybko zbankrutuję.</p>

<h2 id="openrouter-poza-openclaw">OpenRouter poza OpenClaw</h2>

<p>Z OpenRouter można <strong>korzystać również jak ze zwykłego czatu</strong>. Wystarczy wejść na stronę <strong><a href="https://openrouter.ai/chat">https://openrouter.ai/chat</a></strong>. Jednakże nie jest to tak do końca normalny czat. Jako że OpenRouter jest agregatorem modeli LLM to możemy nie tylko przeskakiwać płynnie pomiędzy modelami i zadawać im kolejne pytania na przemian, ale także możemy na raz zadać to samo pytanie do kilku modeli lub włączyć funkcję Auto Router, która sama dopasuje sobie odpowiedni model i w ten sposób optymalizować koszty oraz jakość wyników.</p>

<p>Polecam także zajrzeć do <strong><a href="https://openrouter.ai/rankings">Rankingu modeli</a></strong>, co jest nieocenionym źródłem informacji na temat tego jakie modele aktualnie trendują, czyli są najchętniej używane. W ten sposób można podłapać jaki model aktualnie jest najskuteczniejszy, ale także który najbardziej się opłaca ze względu na stosunek jakości do ceny.</p>

<p>Z kolei <strong><a href="https://openrouter.ai/models">Baza modeli</a></strong> oferuje bardzo rozbudowane i szczegółowe filtry wyszukiwania, co pomaga znaleźć model odpowiedni do wymaganego zastosowania.</p>]]></content><author><name>Tomasz Dunia</name></author><category term="poradniki" /><category term="projekty" /><category term="self-hosting" /><category term="openrouter" /><category term="openclaw" /><category term="hetzner" /><category term="ai" /><category term="llm" /><category term="bot" /><category term="asystent" /><category term="assistant" /><category term="gemini" /><category term="chatgpt" /><category term="claude" /><category term="openai" /><category term="anthropic" /><category term="google" /><category term="vps" /><category term="ssh" /><category term="telegram" /><category term="api" /><summary type="html"><![CDATA[🇵🇱-&gt;🇬🇧 Go to english version of this post / Przejdź do angielskiej wersji tego wpisu]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/openrouter.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/openrouter.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">OpenClaw - Personal AI Assistant [ENG 🇬🇧]</title><link href="https://blog.tomaszdunia.pl/openclaw-eng/" rel="alternate" type="text/html" title="OpenClaw - Personal AI Assistant [ENG 🇬🇧]" /><published>2026-02-23T00:00:00+00:00</published><updated>2026-02-23T00:00:00+00:00</updated><id>https://blog.tomaszdunia.pl/openclaw-eng</id><content type="html" xml:base="https://blog.tomaszdunia.pl/openclaw-eng/"><![CDATA[<p><a href="https://blog.tomaszdunia.pl/openclaw/">🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post</a></p>

<p>Table of contents:</p>
<ul id="markdown-toc">
  <li><a href="#introduction" id="markdown-toc-introduction">Introduction</a>    <ul>
      <li><a href="#what-is-openclaw" id="markdown-toc-what-is-openclaw">What is OpenClaw?</a></li>
      <li><a href="#a-short-history-and-viral-success" id="markdown-toc-a-short-history-and-viral-success">A short history and viral success</a></li>
      <li><a href="#key-differences-agent-vs-chatbot" id="markdown-toc-key-differences-agent-vs-chatbot">Key differences: Agent vs Chatbot</a></li>
      <li><a href="#what-can-openclaw-do" id="markdown-toc-what-can-openclaw-do">What can OpenClaw do?</a></li>
      <li><a href="#who-needs-this" id="markdown-toc-who-needs-this">Who needs this?</a></li>
      <li><a href="#what-you-will-learn-from-this-post" id="markdown-toc-what-you-will-learn-from-this-post">What you will learn from this post</a></li>
      <li><a href="#what-you-will-not-learn-from-this-post" id="markdown-toc-what-you-will-not-learn-from-this-post">What you will NOT learn from this post</a></li>
      <li><a href="#fasten-your-seatbelts" id="markdown-toc-fasten-your-seatbelts">Fasten your seatbelts…</a></li>
    </ul>
  </li>
  <li><a href="#vps-server---the-assistants-body" id="markdown-toc-vps-server---the-assistants-body">VPS Server - the assistant’s body</a>    <ul>
      <li><a href="#registering-at-hetzner" id="markdown-toc-registering-at-hetzner">Registering at Hetzner</a></li>
      <li><a href="#choosing-a-server" id="markdown-toc-choosing-a-server">Choosing a server</a></li>
      <li><a href="#renting-the-server" id="markdown-toc-renting-the-server">Renting the server</a></li>
      <li><a href="#connecting-to-the-server-via-ssh" id="markdown-toc-connecting-to-the-server-via-ssh">Connecting to the server via SSH</a></li>
      <li><a href="#system-and-packages-update" id="markdown-toc-system-and-packages-update">System and packages update</a></li>
      <li><a href="#creating-a-new-user" id="markdown-toc-creating-a-new-user">Creating a new user</a></li>
      <li><a href="#firewall---network-firewall" id="markdown-toc-firewall---network-firewall">Firewall - network firewall</a></li>
      <li><a href="#fail2ban" id="markdown-toc-fail2ban">Fail2Ban</a></li>
      <li><a href="#ssh-keys" id="markdown-toc-ssh-keys">SSH Keys</a></li>
    </ul>
  </li>
  <li><a href="#ai-model---the-assistants-brain" id="markdown-toc-ai-model---the-assistants-brain">AI Model - the assistant’s brain</a>    <ul>
      <li><a href="#obtaining-an-api-key-from-google-ai-studio" id="markdown-toc-obtaining-an-api-key-from-google-ai-studio">Obtaining an API key from Google AI Studio</a></li>
    </ul>
  </li>
  <li><a href="#starting-the-docker-container---birth-of-the-assistant" id="markdown-toc-starting-the-docker-container---birth-of-the-assistant">Starting the Docker container - birth of the assistant</a>    <ul>
      <li><a href="#preparing-docker" id="markdown-toc-preparing-docker">Preparing Docker</a></li>
      <li><a href="#downloading-the-openclaw-repository" id="markdown-toc-downloading-the-openclaw-repository">Downloading the OpenClaw repository</a></li>
      <li><a href="#environment-configuration" id="markdown-toc-environment-configuration">Environment configuration</a></li>
      <li><a href="#starting-the-container" id="markdown-toc-starting-the-container">Starting the container</a></li>
    </ul>
  </li>
  <li><a href="#control-panel---managing-the-assistant" id="markdown-toc-control-panel---managing-the-assistant">Control panel - managing the assistant</a>    <ul>
      <li><a href="#ssh-tunnel" id="markdown-toc-ssh-tunnel">SSH Tunnel</a></li>
      <li><a href="#logging-into-the-panel" id="markdown-toc-logging-into-the-panel">Logging into the panel</a></li>
      <li><a href="#setting-the-model" id="markdown-toc-setting-the-model">Setting the model</a></li>
    </ul>
  </li>
  <li><a href="#first-conversation" id="markdown-toc-first-conversation">First conversation</a></li>
  <li><a href="#fallback-models" id="markdown-toc-fallback-models">Fallback models</a></li>
  <li><a href="#the-assistants-personality" id="markdown-toc-the-assistants-personality">The assistant’s personality</a>    <ul>
      <li><a href="#personality-files" id="markdown-toc-personality-files">Personality files</a></li>
      <li><a href="#fun-fact" id="markdown-toc-fun-fact">Fun fact</a></li>
      <li><a href="#hint" id="markdown-toc-hint">Hint</a></li>
    </ul>
  </li>
  <li><a href="#assistants-tools-and-skills" id="markdown-toc-assistants-tools-and-skills">Assistant’s tools and skills</a>    <ul>
      <li><a href="#tools-vs-skills" id="markdown-toc-tools-vs-skills">Tools vs Skills</a></li>
      <li><a href="#tools" id="markdown-toc-tools">Tools</a></li>
      <li><a href="#skills" id="markdown-toc-skills">Skills</a></li>
    </ul>
  </li>
  <li><a href="#communication-channel" id="markdown-toc-communication-channel">Communication channel</a>    <ul>
      <li><a href="#installing-telegram-on-the-phone" id="markdown-toc-installing-telegram-on-the-phone">Installing Telegram on the phone</a></li>
      <li><a href="#registering-the-bot-with-botfather" id="markdown-toc-registering-the-bot-with-botfather">Registering the bot with BotFather</a></li>
      <li><a href="#connecting-telegram-to-openclaw" id="markdown-toc-connecting-telegram-to-openclaw">Connecting Telegram to OpenClaw</a></li>
      <li><a href="#securing-access-via-telegram" id="markdown-toc-securing-access-via-telegram">Securing access via Telegram</a></li>
    </ul>
  </li>
  <li><a href="#have-fun" id="markdown-toc-have-fun">Have fun</a></li>
  <li><a href="#update---my-first-impressions" id="markdown-toc-update---my-first-impressions">Update - my first impressions</a></li>
</ul>

<h2 id="introduction">Introduction</h2>

<p>Most of us are used to interfaces like ChatGPT or Gemini — these are brilliant “brains in a jar”. They can write, analyze, and advise, but rarely can they actually do “something” outside the browser window. <strong>OpenClaw</strong> changes this dynamic, pushing the boundary from passive chatbots to autonomous agents.</p>

<h3 id="what-is-openclaw">What is OpenClaw?</h3>

<p>OpenClaw is an <strong>open-source</strong> AI assistant whose main task is proactive operation. Unlike standard chats that wait for a question, OpenClaw has a so-called <strong>heartbeat</strong> — it can independently monitor tasks, remind you about deadlines, or react to changes in the digital environment of its “master” (the user) without their direct intervention at a given moment.</p>

<h3 id="a-short-history-and-viral-success">A short history and viral success</h3>

<p>The project was born at the end of 2025 as the work of <strong>Peter Steinberger</strong>. Before getting its final (or is it…?) name, it went through several stages of evolution. It was previously known as <em>WhatsApp Relay</em>, <em>Clawdbot</em>, or <em>Moltbot</em>. It went viral at the turn of 2025 and 2026 thanks to its simplicity — instead of another app, you use it where you already are: on <strong>WhatsApp</strong>, <strong>Telegram</strong>, or <strong>Discord</strong> (and more). The project’s potential is best evidenced by the fact that in February 2026, <strong>the creator of OpenClaw was recruited by the OpenAI team</strong>, although the project itself remains available to the community. I personally have a (probably naive) hope that this won’t kill the project.</p>

<h3 id="key-differences-agent-vs-chatbot">Key differences: Agent vs Chatbot</h3>

<p>The fundamental difference is <strong>system access at a level similar to a physical user</strong>. Standard chats operate in a secure sandbox on corporate servers. Heck, some LLMs don’t even have real-time access to the Internet. OpenClaw operates wherever you deploy it, e.g., on your own VPS server, and most importantly, it can have full access to the resources of that server. What I mean here is that, for example, it can use a browser and log into services normally using the authentication data provided to it.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Feature</th>
      <th style="text-align: left">Standard Chatbot (ChatGPT/Gemini)</th>
      <th style="text-align: left">OpenClaw</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Interaction</strong></td>
      <td style="text-align: left">Reactive (waits for a prompt)</td>
      <td style="text-align: left">Proactive (initiates contact itself)</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Environment</strong></td>
      <td style="text-align: left">Closed, cloud-based</td>
      <td style="text-align: left">Local/VPS, full file access</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Capabilities</strong></td>
      <td style="text-align: left">Content generation, analysis</td>
      <td style="text-align: left">Executing real tasks</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Privacy</strong></td>
      <td style="text-align: left">Data on provider’s servers</td>
      <td style="text-align: left">Full control over logs and memory</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Interface</strong></td>
      <td style="text-align: left">Dedicated app/web</td>
      <td style="text-align: left">Messengers (WhatsApp, Telegram, Discord, etc.)</td>
    </tr>
  </tbody>
</table>

<h3 id="what-can-openclaw-do">What can OpenClaw do?</h3>

<p>Thanks to the use of the <strong>Model Context Protocol (MCP)</strong>, OpenClaw has access to hundreds of <strong>capabilities</strong>, which are called <strong>skills</strong>. They are created by the community like well-known programming libraries. Examples of such skills include:</p>

<ul>
  <li><strong>Managing calendar and emails</strong> autonomously.</li>
  <li><strong>Fetching data from external systems</strong> (e.g., KSeF hehe) and processing it further.</li>
  <li><strong>Independently writing scripts</strong>, installing them on the server, and running them.</li>
  <li><strong>Buying</strong> cinema tickets.</li>
  <li><strong>Managing your Tinder account</strong> (this was widely discussed exactly in the context of OpenClaw).</li>
</ul>

<p>But believe me, the above examples are truly a drop in the ocean, and anyone who even peaks into the library of available possibilities will be mind-blown.</p>

<h3 id="who-needs-this">Who needs this?</h3>

<p>Well, obviously, <strong>nerds</strong> like us. Besides, who wouldn’t want to have <strong>their own sidekick</strong> who will do (almost) everything they are asked to, and on top of that is a walking encyclopedia because it has read 90% of the Internet. Such an assistant can be a virtual member of a development team and write code at a senior level, but you can also write to it on Telegram: “dude, organize a trip to Warsaw for me,” and it will book your train tickets, check the weather and tell you how to dress, set reminders, and notify all your homies from the capital that next Friday you will be within a 10km radius of them ready to grab a beer.</p>

<h3 id="what-you-will-learn-from-this-post">What you will learn from this post</h3>

<p>In a moment you will read something like a <strong>Proof of Concept</strong>, in which I will show you how to run a working OpenClaw bot as cheaply as possible. The goal is to show <strong>how to do it</strong> and check <strong>if it works</strong>, not to launch an optimized environment perfectly suited for a specific task. OpenClaw is such a versatile tool that it has practically an <strong>infinite number of different applications</strong>. What it can do is essentially limited only by the operator’s imagination. That is why I will roughly show what it is, how to run it, and possibly how this environment can be expanded later, but what and how this tool will be used for, I will leave to you, dear Reader.</p>

<p>To summarize, in this post I will:</p>
<ul>
  <li>guide you by the hand through the process of <strong>renting a VPS server</strong>, the price of which is only <strong>5 dollars a month</strong> (!),</li>
  <li>then we will properly <strong>configure this server together</strong>,</li>
  <li>we will obtain <strong>free API access</strong> to the basic Gemini models from Google AI Studio,</li>
  <li>we will run a <strong>Docker container with the bot</strong> inside,</li>
  <li>we will carry out the <strong>basic configuration</strong>,</li>
  <li>we will <strong>check if it works</strong>,</li>
  <li>we will consider options for <strong>expanding the environment</strong>.</li>
</ul>

<h3 id="what-you-will-not-learn-from-this-post">What you will NOT learn from this post</h3>

<p>I want to put my cards on the table right from the start and tell you what will not be included in this post, so that later no one tells me they read 70 thousand characters and only wasted their time because they didn’t find what they were looking for.</p>

<p>So… I won’t show a detailed configuration or any specific application of such an assistant here, because firstly, everyone has different needs, secondly, I am not entirely sure myself what I will use it for yet, and thirdly, this post will be unpleasantly long even without that. Let’s leave these threads to be discussed in future posts, because if I really take a liking to OpenClaw, and I see a good chance of that, I won’t fail to thoroughly describe every aspect of this coexistence.</p>

<h3 id="fasten-your-seatbelts">Fasten your seatbelts…</h3>

<p>… because we are taking off! Prepare drinks, snacks, and if you don’t have a speed reading course certificate, consider getting a potty too, because this won’t be a short post. I promise from this point on to be fairly focused on the substantive content, without unnecessary b… :)</p>

<h2 id="vps-server---the-assistants-body">VPS Server - the assistant’s body</h2>

<h3 id="registering-at-hetzner">Registering at Hetzner</h3>

<ol>
  <li>To create an account on Hetzner, go to the <strong><a href="https://accounts.hetzner.com/signUp">registration form</a></strong>.</li>
  <li>Provide your <strong>e-mail address</strong>, <strong>password</strong> (twice), accept the <strong>terms and conditions</strong>, and click the <strong>Continue</strong> button.</li>
  <li>An <strong>account activation link</strong> will be sent to your email, so go to your email client and find it. Fun fact - something didn’t work for me the first time, and I only got the email after entering the same data a second time, of course.</li>
  <li>The link from the email will take us to the <strong>next part of the registration form</strong>. Here we must:
    <ul>
      <li>select the account type - <strong>Individual</strong>,</li>
      <li>Title - you can choose Mr. or Ms., but you can also just leave <strong>None</strong>,</li>
      <li>First Name - <strong>first name</strong>,</li>
      <li>Surname - <strong>last name</strong>,</li>
      <li>click the <strong>Continue</strong> button.</li>
    </ul>
  </li>
  <li>The next page is about contact details:
    <ul>
      <li>Street / House number - <strong>street</strong>,</li>
      <li>Postal code - <strong>zip code</strong>,</li>
      <li>City - <strong>city</strong> (note: it didn’t accept Polish characters for me, so I assume it might be the same for the <code class="language-plaintext highlighter-rouge">street</code> field),</li>
      <li>Country - <strong>country</strong>,</li>
      <li>VAT ID - <strong>VAT number</strong>, optional as it mostly applies only to businesses,</li>
      <li>Phone - <strong>phone number</strong> (I think it needs to be preceded by <em>+48</em>),</li>
      <li>Mobile phone - <strong>mobile number</strong> is a strong relic from the times of landline phones, so it’s optional and we leave it empty,</li>
      <li>click the <strong>Continue</strong> button.</li>
    </ul>
  </li>
  <li>The next step is about the billing method:
    <ul>
      <li>select the <strong>currency</strong> - With other services, it’s often the case that from the euro-dollar duo, it’s worth choosing the dollar because services cost e.g. 5 dollars or 5 euros, and I don’t remember times when the dollar was more expensive than the euro. However, in this case, Hetzner converts the amounts and it comes out practically the same, so choose the currency that suits you better, maybe your bank has some preferential exchange rate for one of the currencies (?), I chose the dollar,</li>
      <li>we have three payment methods - <strong>traditional bank transfer</strong>, <strong>credit card</strong>, and <strong>PayPal</strong>, I chose a credit card and provided the details of my Revolut virtual prepaid card (prepaid, meaning it has as many funds as I deposit onto it and no more, which is safe), which I have specifically for such needs
        <ul>
          <li>Card holder - enter the <strong>first and last name</strong> shown on the card,</li>
          <li>Credit card - select the card type, i.e., <strong>Visa</strong>, <strong>MasterCard</strong>, or <strong>American Express</strong>,</li>
          <li>Card number - <strong>card number</strong>,</li>
          <li>Expires Month / Year - <strong>month and year the card is valid until</strong>,</li>
          <li>CVC code - <strong>3-digit CVC security code</strong>,</li>
          <li>decide if you want to save the card details so you don’t have to enter them again in the future, and if so, check the option <em>Hetzner Online has my permission to save my credit card data on my account and to use this information to pay open invoices.</em></li>
        </ul>
      </li>
      <li>click the <strong>Complete</strong> button,</li>
      <li>this will require <strong>confirming the card addition</strong>, in my case through the Revolut app (I got a notification and confirmed it).</li>
    </ul>
  </li>
  <li>Success. We get confirmation that we have successfully completed the registration process.</li>
  <li>HOWEVER, it is highly recommended to add an extra layer of 2FA security, so I recommend clicking <strong>Enable 2FA</strong>. Of course, you don’t have to do this and you can simply ignore this recommendation and go straight to step 15.</li>
  <li>We will be redirected to the account settings, where we again click the yellow <strong>Enable 2FA</strong> button.</li>
  <li>A window will pop up in which we have to enter the account password and check the box to confirm that we understand that if we lose the recovery code, Hetzner will send us a new one by mail and won’t do it in any other way. We confirm all this with the <strong>Enable 2FA</strong> button (how much longer…?).</li>
  <li>We save the <strong>LOGIN</strong> and <strong>KEY</strong> displayed on the screen in a safe place. We can also print them using the button. Then we click <strong>Set up authentication</strong> at the bottom.</li>
  <li>We choose the security method. If you have a <strong>Yubikey</strong>, use it, and if not, you can choose <strong>Mobile device</strong>, and for this you need a phone with a suitable app, e.g., <strong><a href="https://github.com/ente-io/ente/">Ente Auth</a></strong>, which I recommend. I will describe how to do it using the latter method.</li>
  <li>We launch <strong>Ente Auth</strong>, press the <strong>plus button</strong> to add a new item, and select <strong>Scan QR code</strong>. We grant the app access to the camera and <strong>scan the QR code</strong> displayed on the Hetzner page. At this point, a new entry will appear in the phone app. We return to the Hetzner page and enter:
    <ul>
      <li>Description - some short <strong>description</strong> to name our device, you can type something like <em>Ente Auth Pixel 9a</em>,</li>
      <li>Account password - Hetzner account <strong>password</strong>,</li>
      <li>New generated OTP - the current <strong>OTP code</strong> displayed in the Ente Auth app on the phone,</li>
      <li><strong>Add</strong> button.</li>
    </ul>
  </li>
  <li>At this point, we will be logged out and will have to log in again. Therefore, we normally provide the login and password and, of course, click the <strong>Login</strong> button. What we see now is this extra step where we have to provide the current OTP code from the Ente Auth app on our phone. We click the <strong>Verify</strong> button. After logging in successfully, we return to the account security settings, where we see that two-factor authentication has been activated. Our account is definitely 100 times safer with this security than with just a login and password.</li>
  <li>After some time, Hetzner asked me by email for additional identity verification because my account raised some doubts. I had to click the link provided in the email (it was a link to the <strong>Verification</strong> tab in the account settings) and confirm my identity with a document (ID card, driver’s license, passport, and I think something else to choose from…) and a photo of my face. To make it funnier, the automatic verification failed because I think I gained weight or something, and I don’t look like the photo on my ID taken years ago, so I had to additionally wait for human verification, which fortunately took maybe a minute or a maximum of two. Fortunately, the Indian guy who verified it understood that people age and it’s rarely a change for the better. I’m no Krzysztof Ibisz or Tom Cruise.</li>
</ol>

<h3 id="choosing-a-server">Choosing a server</h3>

<p>I chose Hetzner because I don’t know a company that provides servers with a better <strong>price-to-quality ratio</strong>. Simply put - for machines with quite good parameters, Hetzner wants really little money, so it’s an ideal option to test a solution, even for a few months.</p>

<p>Let’s see what the current offer looks like. I recommend using the button at the top, which allows you to set the language (English), currency (I chose USD), and most importantly, the country for which the <strong>VAT</strong> is to be calculated. This will allow us to see the <strong>gross prices</strong>, because by default net prices without tax are presented, and this can be very misleading.</p>

<p>Now we can go to the <a href="https://www.hetzner.com/cloud/"><strong>Cloud</strong></a> tab and scroll down to the <strong>Prices</strong> section. What interests us are servers from the <strong>Shared Cost-Optimized</strong> category, meaning shared and thus price-optimized, which is just a nicer name for servers for cheapskates. Now no one should have any doubts that this is exactly what we were looking for. We can choose from two locations, but for me, <strong>Germany</strong> is a pretty obvious choice due to the fact that, in my opinion, the server room you use should always be as close as possible, and Finland is undoubtedly further away and also connected by a cable running along the bottom of the Baltic Sea. We are lazy and don’t want to mess around with IPv6 problems, so we choose the <strong>IPv4</strong> option even though it’s 74 cents more expensive.</p>

<p>The current (as of February 2026) Hetzner <strong>offer</strong> looks like this:</p>

<p><img src="/images/hetznerprices.png" alt="Hetzner offer" /></p>

<p>What interests us is the cheapest <strong>CX23</strong> server with a processor featuring <strong>2 virtual cores</strong> (vCPU), <strong>4GB</strong> of RAM, and a <strong>40GB</strong> SSD drive. Such a server at the time of writing this post costs <strong>5.03 USD per month</strong> (!), which, converted at the current exchange rate, is about <strong>18 PLN</strong> and some change. It’s hard to disagree that this is an <strong>attractive price</strong>.</p>

<h3 id="renting-the-server">Renting the server</h3>

<ol>
  <li>To rent the chosen server, we go to the user console (<strong>Console</strong>), specifically to the <strong><a href="https://console.hetzner.com/projects">Projects</a></strong> tab.</li>
  <li>We press the large <strong>+ New project</strong> button.</li>
  <li>In the <strong>Name</strong> field, we enter the project name, I typed <strong>OpenClaw</strong>.</li>
  <li>We can now add a server to the newly created project, so in the <strong>OpenClaw</strong> project section, we click the <strong>+ CREATE SERVER</strong> button.</li>
  <li>We will be redirected to the <strong>configurator</strong>, where we will set the server parameters. The configurator will guide us through all the options one by one:
    <ul>
      <li>Type - server type, we already determined earlier that we will choose the <strong>Cost-Optimized</strong> option (i.e., for cheapskates), and in addition, we will go with the <strong>x86 architecture</strong>, because we care about maximum compatibility at the cost of slightly lower performance, finally, we select <strong>CX23</strong> from the list,</li>
      <li>Location - server location, I would have chosen <strong>Falkenstein</strong>, but unfortunately, it wasn’t possible due to temporarily (?) high demand, so for lack of a better option, I’ll take <strong>Nuremberg</strong>,</li>
      <li>Image - system selection, I recommend <strong>Ubuntu 24.04</strong>, because as I mentioned earlier, we want maximum compatibility, and Ubuntu is like tomato soup, most people (in this case, software) like it,</li>
      <li>Networking - we select <strong>Public IPv4</strong>, which incurs an additional fee, but we already discussed that, and <strong>Public IPv6</strong>, which happens to be included in the price, however, we do not select <strong>Private networks</strong>,</li>
      <li>SSH keys - in this section, we can create an SSH key, but if we don’t do it, Hetzner will simply send us the password by email, which suits us for now, because <strong>we will deal with SSH keys later during server configuration</strong>,</li>
      <li>Volumes - <strong>we skip this</strong>, because our server basically already has 40GB of storage for data,</li>
      <li>Firewalls - <strong>we skip this</strong> at this stage, because we will create a firewall from the server level during its configuration,</li>
      <li>Backups - if someone is interested in daily backups, this option costs an additional 0.86 USD per month, I don’t need it, so <strong>I skipped this section</strong>,</li>
      <li>Placement groups - here you can create server clusters, but we don’t need that, so <strong>we skip it</strong>,</li>
      <li>Labels - I’m not knowledgeable enough to comment on what this is, so <strong>I skip it</strong>,</li>
      <li>Cloud config - I’m not knowledgeable enough to comment on what this is, so <strong>I skip it</strong>,</li>
      <li>Name - here we give our server a name, I typed <strong>openclaw-assistant</strong></li>
    </ul>
  </li>
  <li>
    <p>The configuration should look more or less like this:</p>

    <p><img src="/images/hetznerserverconfig.png" alt="Server configuration for purchase" /></p>
  </li>
  <li>With such a configuration, we can proceed to purchase the server. To do this, we press the red <strong>Create &amp; Buy now</strong> button.</li>
  <li>We will be taken to the list of our servers, where a new (and the only) option will appear, i.e., the server we just created. At first, there will be a spinning circle next to it, which means we have to wait a moment for it to be created. However, after a while, a green <strong>Server created</strong> message will pop up at the bottom, meaning that our testing ground is ready.</li>
</ol>

<h3 id="connecting-to-the-server-via-ssh">Connecting to the server via SSH</h3>

<p>The server is ready, so it’s time to check our email, where there should already be a message with all the information needed to connect to it. It should look more or less like this:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
Your new server

Your server "openclaw-assistant" was created!

You can access your server with the following credentials:
 
IPv4      ADRES_IPV4/32
IPv6      ADRES_IPV6/64
User      root
Password  OCENZUROWANE_HASŁO
	
You will be prompted to change your password on your first login.

To improve security, we recommend that you add an SSH key when creating a server. This way, no root password will be set and this e-mail won't be generated. 

</code></pre></div></div>

<p>From this email, we will further need <strong>ADRES_IPV4</strong> and <strong>OCENZUROWANE_HASŁO</strong> (CENSORED_PASSWORD). Let’s try connecting to the server now.</p>
<ol>
  <li>
    <p>On our computer, we open the <strong>terminal</strong> and type:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh root@ADRES_IPV4
</code></pre></div>    </div>
  </li>
  <li>
    <p>We should see this <strong>message</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    
 The authenticity of host <span class="s1">'ADRES_IPV4 (ADRES_IPV4)'</span> cant be established.
 ED25519 key fingerprint is SHA256: CENZURA.
 This key is not known by any other names.
 Are you sure you want to <span class="k">continue </span>connecting <span class="o">(</span><span class="nb">yes</span>/no/[fingerprint]<span class="o">)</span>?
    
</code></pre></div>    </div>
  </li>
  <li>We must answer this by typing <strong>yes</strong> and pressing <strong>ENTER</strong>.</li>
  <li>
    <p>The result will be a message informing us that our server’s address has been added to the list of known hosts and next time it will be recognized by its fingerprint, and there will be no need to confirm its authenticity.</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Warning: Permanently added <span class="s1">'ADRES_IPV4'</span> <span class="o">(</span>ED25519<span class="o">)</span> to the list of known hosts.
 Connection closed by ADRES_IPV4 port 22
</code></pre></div>    </div>
  </li>
  <li>
    <p>The connection will be dropped, so we have to use the <strong>command</strong> once again:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh root@ADRES_IPV4
</code></pre></div>    </div>
  </li>
  <li>We will be greeted by a prompt to enter the password, so we type the <strong>OCENZUROWANE_HASŁO</strong> and confirm with <strong>ENTER</strong>. Note: if you have no experience with SSH, you might be surprised that when typing the password, nothing happens, i.e., not even asterisks appear; this is how it’s supposed to be and it’s the desired behavior, just type the password and don’t worry about it.</li>
  <li>
    <p>If we didn’t mess anything up, we should successfully establish a connection and be <strong>greeted</strong> by something like:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> You are required to change your password immediately <span class="o">(</span>administrator enforced<span class="o">)</span><span class="nb">.</span>
 Welcome to Ubuntu 24.04.3 LTS <span class="o">(</span>GNU/Linux 6.8.0-90-generic x86_64<span class="o">)</span>

 <span class="k">*</span> Documentation:  <span class="o">[</span>https://help.ubuntu.com]<span class="o">(</span>https://help.ubuntu.com<span class="o">)</span>
 <span class="k">*</span> Management:     <span class="o">[</span>https://landscape.canonical.com]<span class="o">(</span>https://landscape.canonical.com<span class="o">)</span>
 <span class="k">*</span> Support:        <span class="o">[</span>https://ubuntu.com/pro]<span class="o">(</span>https://ubuntu.com/pro<span class="o">)</span>

 System information as of Thu Feb 19 07:43:22 PM UTC 2026

 System load:              0.16              
 Processes:                127
 Usage of /:               4.1% of 37.23GB   
 Users logged <span class="k">in</span>:          0
 Memory usage:             5%                
 IPv4 address <span class="k">for </span>eth0:    ADRES_IPV4
 Swap usage:               0%                
 IPv6 address <span class="k">for </span>eth0:    ADRES_IPV6

 Expanded Security Maintenance <span class="k">for </span>Applications is not enabled.

 62 updates can be applied immediately.
 43 of these updates are standard security updates.
 To see these additional updates run: apt list <span class="nt">--upgradable</span>

 Enable ESM Apps to receive additional future security updates.
 See <span class="o">[</span>https://ubuntu.com/esm]<span class="o">(</span>https://ubuntu.com/esm<span class="o">)</span> or run: <span class="nb">sudo </span>pro status

 Changing password <span class="k">for </span>root.
 Current password: 
</code></pre></div>    </div>
  </li>
  <li>The server is configured in such a way that it <strong>forces us to change the administrator password</strong> right during the first connection. This is a good practice, so we obediently follow the suggestion.
    <ul>
      <li>first, we enter the old <strong>OCENZUROWANE_HASŁO</strong> and confirm with <strong>ENTER</strong>,</li>
      <li>and then we enter the <strong>NOWE_HASŁO</strong> (NEW_PASSWORD) twice, confirming each time with <strong>ENTER</strong>.</li>
    </ul>
  </li>
</ol>

<h3 id="system-and-packages-update">System and packages update</h3>

<p>We will start the basic configuration by <strong>updating the packages on the server</strong>. For this, we will use a ready-made little script that I previously presented in <a href="https://blog.tomaszdunia.pl/serwer-domowy-podstawowa-konfiguracja/#aktualizacja-to-podstawa">one of the posts on this blog</a>.</p>

<ol>
  <li>
    <p>We type the <strong>command</strong> that creates the appropriate file and opens it:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> nano /usr/local/sbin/aktualizacja.sh
</code></pre></div>    </div>
  </li>
  <li>
    <p>In the editor, <strong>we paste the following content</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    
 <span class="c">#!/bin/bash</span>
 <span class="c">#Script for updating the system and packages from blog.tomaszdunia.pl</span>
 <span class="nb">echo</span> <span class="s1">'Step 1 - update'</span>
 <span class="nb">sudo </span>apt update
 <span class="nb">echo</span> <span class="s1">'Step 2 - upgrade'</span>
 <span class="nb">sudo </span>apt upgrade <span class="nt">-y</span>
 <span class="nb">echo</span> <span class="s1">'Step 3 - autoremove'</span>
 <span class="nb">sudo </span>apt autoremove <span class="nt">-y</span>
 <span class="nb">echo</span> <span class="s1">'Step 4 - clean'</span>
 <span class="nb">sudo </span>apt clean
    
</code></pre></div>    </div>
  </li>
  <li>
    <p>We exit the file with the <strong>Control (CTRL) + X</strong> key combination, we will be asked if we want to save the file in this state, we confirm by pressing <strong>y</strong>, and when asked under what name to save it, we simply press <strong>ENTER</strong>, because we don’t want to change it.</p>
  </li>
  <li>
    <p>Let’s give this script executable permissions:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">chmod</span> +x /usr/local/sbin/aktualizacja.sh
</code></pre></div>    </div>
  </li>
  <li>
    <p>Now just type the file name as a command to start the automatic update and cleanup process:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> aktualizacja.sh
</code></pre></div>    </div>
  </li>
  <li>
    <p>After completing such a large update (I assume that many packages will be outdated right after the first server startup), it’s good to consider restarting the server:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> reboot
</code></pre></div>    </div>
  </li>
  <li>
    <p>Of course, we will lose the connection to the server, so we will have to establish it just like we did earlier.</p>
  </li>
</ol>

<h3 id="creating-a-new-user">Creating a new user</h3>

<p>The basis of sensibly using a VPS server is <strong>not working on the root user</strong>. Therefore, we will now create a regular user and assign them to a group capable of executing administrative commands. This is like an administrator, but with an extra layer of security, because before executing an administrative command, they will have to type <strong>sudo</strong> and confirm with a <strong>password</strong>. This is sometimes enough to <strong>come to your senses before doing something stupid</strong>. Creating such an account is standard practice. We will name it <strong>manager</strong>.</p>

<ol>
  <li>
    <p>We create a user named <strong>manager</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> adduser manager
</code></pre></div>    </div>
  </li>
  <li>The server will inform us that it has created a new user and group, assigned them unique IDs, and created a home directory. We will also be asked to provide the <strong>password for the new user</strong> twice.</li>
  <li>Next, the wizard will want to extract unnecessary data from us, such as first and last name, room number, phone, etc., which does not interest us, so we leave all fields blank and just confirm with <strong>ENTER</strong>. All this will also need to be confirmed with <strong>y</strong>.</li>
  <li>
    <p>The user is created, so now we need to add them to the administrators group:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> usermod <span class="nt">-aG</span> <span class="nb">sudo </span>manager
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="firewall---network-firewall">Firewall - network firewall</h3>

<p>Let’s configure the <strong>firewall</strong>. A good practice is to initially <strong>block all incoming traffic</strong>, <strong>allow all outgoing traffic</strong>, and also <strong>open port 22</strong> (default for SSH).</p>

<ol>
  <li>
    <p>Let’s start by installing <strong>ufw</strong> (short for Uncomplicated Firewall), it’s a wrapper for <strong>iptables</strong> that makes creating firewall rules a bit more pleasant:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> apt <span class="nb">install </span>ufw
</code></pre></div>    </div>
  </li>
  <li>
    <p>Now we will execute a few commands one after the other. We <strong>disable</strong> the firewall to change its settings:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ufw disable
</code></pre></div>    </div>
  </li>
  <li>
    <p>We will <strong>reset</strong> (clear) all rules to start completely from scratch, this will need to be confirmed with <strong>y</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ufw reset
</code></pre></div>    </div>
  </li>
  <li>
    <p>We will block all <strong><em>incoming</em> traffic</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ufw default deny incoming
</code></pre></div>    </div>
  </li>
  <li>
    <p>We will allow all <strong>outgoing</strong> traffic:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ufw default allow outgoing
</code></pre></div>    </div>
  </li>
  <li>
    <p>We will open <strong>port 22</strong> for SSH connections:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ufw allow 22
</code></pre></div>    </div>
  </li>
  <li>
    <p>We will <strong>enable</strong> the firewall, this requires confirming with <strong>y</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ufw <span class="nb">enable</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>Now, even if we broke something, we won’t lose the connection to the server, but at most, we won’t be able to connect to it after dropping the connection. So let’s take this moment and <strong>check a second time if everything is set up exactly as we wanted</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ufw status verbose
</code></pre></div>    </div>
  </li>
  <li>
    <p>The output of this command <strong>must be</strong> as follows:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Status: active
 Logging: on <span class="o">(</span>low<span class="o">)</span>
 Default: deny <span class="o">(</span>incoming<span class="o">)</span>, allow <span class="o">(</span>outgoing<span class="o">)</span>, disabled <span class="o">(</span>routed<span class="o">)</span>
 New profiles: skip

 To          Action      From
 <span class="nt">--</span>          <span class="nt">------</span>      <span class="nt">----</span>
 22          ALLOW IN    Anywhere                  
 22 <span class="o">(</span>v6<span class="o">)</span>     ALLOW IN    Anywhere <span class="o">(</span>v6<span class="o">)</span>
</code></pre></div>    </div>
  </li>
  <li>If everything matches <strong>to the letter</strong>, you can rest easy.</li>
  <li>
    <p>Let’s also check if <code class="language-plaintext highlighter-rouge">ufw</code> will definitely <strong>start up with the system</strong> after every reboot. Let’s look into the file:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/ufw/ufw.conf
</code></pre></div>    </div>
  </li>
  <li>
    <p>Inside we should find the following content:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    
<span class="c"># /etc/ufw/ufw.conf</span>
<span class="c">#</span>
<span class="c"># Set to yes to start on boot. If setting this remotely, be sure to add a rule</span>
<span class="c"># to allow your remote connection before starting ufw. Eg: 'ufw allow 22/tcp'</span>
<span class="nv">ENABLED</span><span class="o">=</span><span class="nb">yes</span>

<span class="c"># Please use the 'ufw' command to set the loglevel. Eg: 'ufw logging medium'.</span>
<span class="c"># See 'man ufw' for details.</span>
<span class="nv">LOGLEVEL</span><span class="o">=</span>low
    
</code></pre></div>    </div>
  </li>
  <li>The <strong>ENABLED</strong> variable is important to us. Its value must be <strong>yes</strong>, and the line in which it appears cannot be commented out (no # at the beginning).</li>
  <li>We exit the file with the combination <strong>Control (CTRL) + X</strong>.</li>
</ol>

<h3 id="fail2ban">Fail2Ban</h3>

<p>This is a program that protects against <strong>brute force</strong> attacks. If someone tries to guess the SSH password several times in a row and fails, <code class="language-plaintext highlighter-rouge">Fail2Ban</code> will automatically <strong>block their IP address</strong>.</p>

<ol>
  <li>
    <p>We <strong>install</strong> the program:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> apt <span class="nb">install </span>fail2ban <span class="nt">-y</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>We <strong>enable</strong> it:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> systemctl <span class="nb">enable </span>fail2ban <span class="nt">--now</span>
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="ssh-keys">SSH Keys</h3>

<p>I will not debate why using SSH keys is a <strong>recommended practice</strong>. I will just show how to configure it.</p>

<ol>
  <li>
    <p>Let’s start, however, by <strong>logging out</strong> of the root account:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">exit</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>Now let’s connect with the <strong>target account for managing the server</strong> to check if everything works properly:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh manager@ADRES_IPV4
</code></pre></div>    </div>
  </li>
  <li>Remember that now you must <strong>enter the password that was provided when creating this user</strong>, not the root password.</li>
  <li>
    <p>If you managed to connect and authenticate, it means that <strong>everything is OK</strong> and we can <strong>disconnect</strong> again and return to the local terminal:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">exit</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>Let’s now <strong>create an SSH key pair</strong> (command to be executed on the local computer!):</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-C</span> openclaw-assistant
</code></pre></div>    </div>
  </li>
  <li>
    <p>The script will ask for the path and file name where the key should be saved. The <strong>default value suits us</strong>, so we just confirm with <strong>ENTER</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Enter file <span class="k">in </span>which to save the key <span class="o">(</span>/root/.ssh/id_ed25519<span class="o">)</span>: 
</code></pre></div>    </div>
  </li>
  <li>
    <p>Then it will ask to set a <strong>passphrase to secure the key</strong>, I recommend doing this, but <strong>let it be something rather simple</strong> that will be easy for us to remember, it’s just an extra layer of security in case our computer with the key on the disk falls into the wrong hands and is unlocked on top of that. For me, this is a scenario in which losing SSH keys will be my smallest problem, so I turn a blind eye to such an attack vector. Hence the simple passphrase. You can also not set a passphrase at all and just skip this step by pressing <strong>ENTER</strong> twice.</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Enter passphrase <span class="o">(</span>empty <span class="k">for </span>no passphrase<span class="o">)</span>: 
 Enter same passphrase again: 
</code></pre></div>    </div>
  </li>
  <li>
    <p>Now let’s send the freshly generated <strong>keys to the VPS server</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh-copy-id manager@ADRES_IPV4
</code></pre></div>    </div>
  </li>
  <li>
    <p>This one last time we will be asked to <strong>provide the password</strong> of the <code class="language-plaintext highlighter-rouge">manager</code> user when logging in. <strong>Keys sent</strong>, and now we can test <strong>logging in without having to provide a password</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh manager@ADRES_IPV4
</code></pre></div>    </div>
  </li>
  <li>
    <p>Now we will perform two important steps - we will <strong>disable password login</strong>, meaning from now on you will be able to access the server <strong>only by having a private SSH key</strong>, and we will <strong>disable the ability to log into the root account</strong>. To do this, we edit the file:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>nano /etc/ssh/sshd_config
</code></pre></div>    </div>
  </li>
  <li>
    <p>We look for the parameters <code class="language-plaintext highlighter-rouge">PermitRootLogin</code>, <code class="language-plaintext highlighter-rouge">PubkeyAuthentication</code>, and <code class="language-plaintext highlighter-rouge">PasswordAuthentication</code> (note - they will not be next to each other), we check if they are not commented out (they must not have a # at the beginning of the line), and we <strong>change their values</strong> to the following:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PermitRootLogin no
...
PubkeyAuthentication <span class="nb">yes</span>
...
PasswordAuthentication no
</code></pre></div>    </div>
  </li>
  <li>We save and exit the file - <strong>Control (CTRL) + X</strong>, then <strong>y</strong> and <strong>ENTER</strong>.</li>
  <li>
    <p>We <strong>restart</strong> the <code class="language-plaintext highlighter-rouge">ssh</code> process to apply the changes:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>service ssh restart
</code></pre></div>    </div>
  </li>
</ol>

<h2 id="ai-model---the-assistants-brain">AI Model - the assistant’s brain</h2>

<p>You can connect many different LLM models to OpenClaw. It supposedly works best with <strong><a href="https://claude.com/pricing#api">Claude Sonnet</a></strong> from <strong>Anthropic</strong>, but it is a paid solution and, moreover, billed based on usage (price per tokens), which somewhat clashes with the idea of doing this as a trial, and thus as cheaply as possible. <strong>Google Gemini</strong> comes to the rescue here, which, as part of the <strong>Free tier</strong> plan in <strong><a href="https://aistudio.google.com/">Google AI Studio</a></strong>, is a <strong>free</strong> solution and will be sufficient for our application. Smells fishy, right? You can explain this away as Google’s fight against the competition from OpenAI and Anthropic, but let’s not kid ourselves that there’s really anything for free, because by using the Free Tier plan in Google AI Studio, we are actually paying with the currency of our data, which will be used to train the behemoth’s models. Of course, they will be anonymized and so on… As they say, if it’s free, even vinegar is sweet, and after all, we are here to check how it works in the first place. Besides, I don’t know about you, but I don’t plan to touch any confidential data in this experiment, so I don’t really care if anyone analyzes the nonsense I throw into the tested assistant.</p>

<p>If OpenClaw turns out to be an amazing invention, we can easily switch to Claude later, or use <strong><a href="https://openrouter.ai/">OpenRouter</a></strong> altogether, which will allow us to seamlessly switch between different models.</p>

<p>It is also worth mentioning that the free plan from Google obviously has <strong>usage limits</strong>:</p>
<ul>
  <li><strong>RPM</strong> (Requests Per Minute) - limit of requests per minute,</li>
  <li><strong>TPM</strong> (Tokens Per Minute) - limit of words/data (tokens) per minute,</li>
  <li><strong>RPD</strong> (Requests Per Day) - limit of requests per day.</li>
</ul>

<p>The limits available for your account can be checked in <strong><a href="https://aistudio.google.com/rate-limit?timeRange=this-month">Dashboard -&gt; Rate Limit</a></strong>. I recommend focusing on the <strong>Rate limits by model</strong> section and sorting the table by the model name, i.e., the <strong>Model</strong> column. There are quite a few different models there, but we are essentially only interested in those signed <strong>Gemini</strong>, meaning from the <strong>Text-out models</strong> category. At the time of writing this post, the limits for the <strong>Free tier</strong> plan look like this for me:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Model</th>
      <th style="text-align: left">Category</th>
      <th style="text-align: left">RPM</th>
      <th style="text-align: left">TPM</th>
      <th style="text-align: left">RPD</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>Gemini 2.5 Flash</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 5</td>
      <td style="text-align: left">0 / 250K</td>
      <td style="text-align: left">0 / 20</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Gemini 2.5 Pro</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Gemini 2 Flash</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Gemini 2 Flash Exp</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Gemini 2 Flash Lite</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Gemini 2 Pro Exp</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Gemini 3 Flash</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 5</td>
      <td style="text-align: left">0 / 250K</td>
      <td style="text-align: left">0 / 20</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Gemini 2.5 Flash Lite</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 10</td>
      <td style="text-align: left">0 / 250K</td>
      <td style="text-align: left">0 / 20</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Gemini 3 Pro</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Gemini 3.1 Pro</strong></td>
      <td style="text-align: left">Text-out models</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
      <td style="text-align: left">0 / 0</td>
    </tr>
  </tbody>
</table>

<p>As you can see, the restrictions are quite severe. In the free plan, we basically only have access to three models:</p>
<ul>
  <li><strong>Gemini 2.5 Flash</strong></li>
  <li><strong>Gemini 3 Flash</strong></li>
  <li><strong>Gemini 2.5 Flash Lite</strong></li>
</ul>

<p>In addition, when it comes to limits, we have 5-10 requests per minute, 250k tokens (which doesn’t say much), and only 20 requests per day. This is very poor, but it should be enough to test the bot.</p>

<h3 id="obtaining-an-api-key-from-google-ai-studio">Obtaining an API key from Google AI Studio</h3>

<ol>
  <li>Go to the <strong><a href="https://aistudio.google.com/">Google AI Studio</a></strong> website and press the <strong>Get started</strong> button in the top right corner.</li>
  <li><strong>Log in</strong> with our Google account.</li>
  <li>From the menu on the bottom left, select <strong><a href="https://aistudio.google.com/api-keys">Get API key</a></strong>.</li>
  <li>Press the <strong>Create API key</strong> button located at the top right.</li>
  <li>In the <strong>Name your key</strong> field, enter a name for the key, it can be e.g., <code class="language-plaintext highlighter-rouge">OpenClaw Assistant</code>. From the <strong>Choose an imported project</strong> list, select <strong>+ Create project</strong>, give it a name, e.g., <code class="language-plaintext highlighter-rouge">OpenClaw Project</code>, and press <strong>Create project</strong>. Then press <strong>Create key</strong>.</li>
  <li>An item with the name we entered will appear on the list of keys. On the right side, we have a few icons, and the first one from the left is called <strong>Copy API key</strong>, and this is exactly what we use.</li>
  <li>Save the copied key in a safe place.</li>
</ol>

<h2 id="starting-the-docker-container---birth-of-the-assistant">Starting the Docker container - birth of the assistant</h2>

<p>It’s time to take action. OpenClaw even has a <a href="https://docs.openclaw.ai/install/hetzner">special subsection in its documentation regarding running the service based on Docker on a Hetzner server</a>. We will base our setup on it.</p>

<h3 id="preparing-docker">Preparing Docker</h3>

<ol>
  <li>
    <p>We return to the VPS server and <strong>log in</strong> as the <code class="language-plaintext highlighter-rouge">manager</code> user:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh manager@ADRES_IPV4
</code></pre></div>    </div>
  </li>
  <li>
    <p>We install the necessary <strong>packages</strong> - <code class="language-plaintext highlighter-rouge">Docker</code>, <code class="language-plaintext highlighter-rouge">Docker Compose</code>, and <code class="language-plaintext highlighter-rouge">Git</code>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> docker.io docker-compose-v2 git
</code></pre></div>    </div>
  </li>
  <li>
    <p>To manage containers without having to repeatedly type <code class="language-plaintext highlighter-rouge">sudo</code> before commands, we will <strong>add the user</strong> <code class="language-plaintext highlighter-rouge">manager</code> <strong>to the group</strong> <code class="language-plaintext highlighter-rouge">docker</code>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>usermod <span class="nt">-aG</span> docker manager
</code></pre></div>    </div>
  </li>
  <li>
    <p>For the new permissions to take effect, we must <strong>log out</strong> using the <code class="language-plaintext highlighter-rouge">exit</code> command and <strong>reconnect</strong> to the server:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh manager@ADRES_IPV4
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="downloading-the-openclaw-repository">Downloading the OpenClaw repository</h3>

<ol>
  <li>
    <p>Before executing the next command, <strong>check if the link below is still valid at the time you are reading this</strong>. I’m writing about this because with the OpenClaw project, the name has already been changed 3 or 4 times, and once even third parties managed to take over the project’s domain, which is a insanely <strong>dangerous practice</strong>. If you have any doubts, you can always feel free to write to me directly on Mastodon or in a comment to this post. Once we know we have a good <strong>link to the repository, we download</strong> it to our server:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> git clone <span class="o">[</span>https://github.com/openclaw/openclaw.git]<span class="o">(</span>https://github.com/openclaw/openclaw.git<span class="o">)</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>We go to the downloaded <strong>folder</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">cd </span>openclaw
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="environment-configuration">Environment configuration</h3>

<ol>
  <li>
    <p>Now we define a <strong>persistent directory</strong>. Docker deletes data upon restart. For the bot to <strong>retain its memory</strong> (logins, settings, etc.), we must create an appropriate folder on the server where they will be permanently maintained:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">mkdir</span> <span class="nt">-p</span> /home/manager/.openclaw/workspace
</code></pre></div>    </div>
  </li>
  <li>
    <p>We still need to <strong>grant them the appropriate permissions</strong> of the container’s internal user (UID 1000):</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">chown</span> <span class="nt">-R</span> 1000:1000 /home/manager/.openclaw
</code></pre></div>    </div>
  </li>
  <li>
    <p>Let’s configure the <strong>environment</strong>. For this purpose, we create a <code class="language-plaintext highlighter-rouge">.env</code> file:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> nano .env
</code></pre></div>    </div>
  </li>
  <li>
    <p>We paste the following as the <strong>file content</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nv">OPENCLAW_IMAGE</span><span class="o">=</span>openclaw:latest
 <span class="nv">OPENCLAW_GATEWAY_TOKEN</span><span class="o">=</span>TWÓJ_TOKEN
 <span class="nv">OPENCLAW_GATEWAY_BIND</span><span class="o">=</span>lan
 <span class="nv">OPENCLAW_GATEWAY_PORT</span><span class="o">=</span>18789
 <span class="nv">OPENCLAW_CONFIG_DIR</span><span class="o">=</span>/home/manager/.openclaw
 <span class="nv">OPENCLAW_WORKSPACE_DIR</span><span class="o">=</span>/home/manager/.openclaw/workspace
 <span class="nv">GOG_KEYRING_PASSWORD</span><span class="o">=</span>TWÓJ_KLUCZ
 <span class="nv">XDG_CONFIG_HOME</span><span class="o">=</span>/home/node/.openclaw
 <span class="nv">GEMINI_API_KEY</span><span class="o">=</span>KLUCZ_API_GEMINI
</code></pre></div>    </div>
  </li>
  <li>We don’t close the file yet, because it is necessary to <strong>modify</strong> three things in it:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">TWÓJ_TOKEN</code> (YOUR_TOKEN) - instead of this, enter some complex string of characters, which you will also save in your password manager; this will be the <strong>access password to the control panel</strong> (Control UI) of the bot.</li>
      <li><code class="language-plaintext highlighter-rouge">TWÓJ_KLUCZ</code> (YOUR_KEY) - instead of this, enter some complex string of characters, which you will also save in your password manager; this will be the <strong>key with which the data in the persistent directory</strong> <code class="language-plaintext highlighter-rouge">(...)/.openclaw/workspace</code> that we created earlier will be encrypted; thanks to this, even if someone breaks into the VPS and copies this folder, they will not read the confidential data stored there.</li>
      <li><code class="language-plaintext highlighter-rouge">KLUCZ_API_GEMINI</code> (GEMINI_API_KEY) - instead of this, provide the <strong>API key</strong> that we copied earlier from Google AI Studio.</li>
      <li><strong>NOTE</strong> - when generating the token and key, be careful not to include the <code class="language-plaintext highlighter-rouge">$</code> sign in the character string, because it crashed my container during its build and I lost probably an hour looking for the problem.</li>
    </ul>
  </li>
  <li>Now we can save and close the environment configuration file - <strong>Control (CTRL) + X</strong>, then <strong>y</strong> and <strong>ENTER</strong>.</li>
  <li>Before we build the container, we still need to <strong>modify the default file</strong> <code class="language-plaintext highlighter-rouge">docker-compose.yml</code>, because our case differs slightly from the one assumed as default in the main repository.</li>
  <li>
    <p>Before modifying the file, it is better to <strong>make a backup copy of it</strong>, so that in case of anything you can refer to its original content:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">cp </span>docker-compose.yml docker-compose-old-backup.yml
</code></pre></div>    </div>
  </li>
  <li>
    <p>We <strong>open</strong> the <code class="language-plaintext highlighter-rouge">docker-compose.yml</code> file in the editor:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> nano docker-compose.yml
</code></pre></div>    </div>
  </li>
  <li>
    <p>The <strong>correct content</strong> should be as follows:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	
services:
    openclaw-gateway:
        image: <span class="k">${</span><span class="nv">OPENCLAW_IMAGE</span><span class="k">}</span>
        build: <span class="nb">.</span>
        restart: unless-stopped
        env_file:
            - .env
        environment:
            - <span class="nv">HOME</span><span class="o">=</span>/home/node
            - <span class="nv">NODE_ENV</span><span class="o">=</span>production
            - <span class="nv">TERM</span><span class="o">=</span>xterm-256color
            - <span class="nv">OPENCLAW_GATEWAY_BIND</span><span class="o">=</span><span class="k">${</span><span class="nv">OPENCLAW_GATEWAY_BIND</span><span class="k">}</span>
            - <span class="nv">OPENCLAW_GATEWAY_PORT</span><span class="o">=</span><span class="k">${</span><span class="nv">OPENCLAW_GATEWAY_PORT</span><span class="k">}</span>
            - <span class="nv">OPENCLAW_GATEWAY_TOKEN</span><span class="o">=</span><span class="k">${</span><span class="nv">OPENCLAW_GATEWAY_TOKEN</span><span class="k">}</span>
            - <span class="nv">GOG_KEYRING_PASSWORD</span><span class="o">=</span><span class="k">${</span><span class="nv">GOG_KEYRING_PASSWORD</span><span class="k">}</span>
            - <span class="nv">XDG_CONFIG_HOME</span><span class="o">=</span><span class="k">${</span><span class="nv">XDG_CONFIG_HOME</span><span class="k">}</span>
            - <span class="nv">PATH</span><span class="o">=</span>/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
        volumes:
            - <span class="k">${</span><span class="nv">OPENCLAW_CONFIG_DIR</span><span class="k">}</span>:/home/node/.openclaw
            - <span class="k">${</span><span class="nv">OPENCLAW_WORKSPACE_DIR</span><span class="k">}</span>:/home/node/.openclaw/workspace
        ports:
            - <span class="s2">"127.0.0.1:</span><span class="k">${</span><span class="nv">OPENCLAW_GATEWAY_PORT</span><span class="k">}</span><span class="s2">:18789"</span>
        <span class="nb">command</span>:
            - <span class="s2">"node"</span>
            - <span class="s2">"dist/index.js"</span>
            - <span class="s2">"gateway"</span>
            - <span class="s2">"--bind"</span>
            - <span class="s2">"</span><span class="k">${</span><span class="nv">OPENCLAW_GATEWAY_BIND</span><span class="k">}</span><span class="s2">"</span>
            - <span class="s2">"--port"</span>
            - <span class="s2">"</span><span class="k">${</span><span class="nv">OPENCLAW_GATEWAY_PORT</span><span class="k">}</span><span class="s2">"</span>
            - <span class="s2">"--allow-unconfigured"</span>
	
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="starting-the-container">Starting the container</h3>

<ol>
  <li>
    <p>The time has come to <strong>build the container</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose build
</code></pre></div>    </div>
  </li>
  <li>
    <p>Now all that’s left is to <strong>wait</strong> patiently. In my case, the process took 174 seconds.</p>
  </li>
  <li>
    <p>If the container was built successfully (green <code class="language-plaintext highlighter-rouge">built</code> message), we can <strong>try to start it</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose up <span class="nt">-d</span> openclaw-gateway
</code></pre></div>    </div>
  </li>
  <li>
    <p>Let’s check now <strong>if the container has started</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker ps
</code></pre></div>    </div>
  </li>
  <li>
    <p>One item named <code class="language-plaintext highlighter-rouge">openclaw-openclaw-gateway-1</code> should appear on the list, and in the <code class="language-plaintext highlighter-rouge">Status</code> column there should be <code class="language-plaintext highlighter-rouge">Up ...</code> informing how long ago the container “got up”.</p>
  </li>
  <li>
    <p>Let’s also check the <strong>logs</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose logs <span class="nt">-f</span> openclaw-gateway
</code></pre></div>    </div>
  </li>
  <li>
    <p>If there are no red <code class="language-plaintext highlighter-rouge">WARNING</code> or <code class="language-plaintext highlighter-rouge">ERROR</code> messages there, it might mean that <strong>everything is OK</strong>. I don’t require anyone to understand what is written there, because I certainly don’t understand it fully myself. If you have doubts, you can send me the content of the logs, throw them here in a comment, or ask e.g., Gemini about it ( :-) ). We exit the logs with the <strong>Control (CTRL) + C</strong> key combination.</p>
  </li>
</ol>

<h2 id="control-panel---managing-the-assistant">Control panel - managing the assistant</h2>

<p>The container has been started, so it’s time to go inside and try to make the first attempt at contact with the bot running inside. Specifically, we will enter the panel from which we will manage the bot.</p>

<h3 id="ssh-tunnel">SSH Tunnel</h3>

<ol>
  <li>
    <p>For security reasons, <strong>we previously blocked access to the server from the outside</strong> (except for port 22, i.e., SSH). Therefore, to get inside the created environment, we need to <strong>set up an SSH tunnel</strong>. To do this, in the terminal on the local computer (not on the server), we type:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh <span class="nt">-N</span> <span class="nt">-L</span> 18789:127.0.0.1:18789 manager@ADRES_IPV4
</code></pre></div>    </div>
  </li>
  <li>Don’t be surprised, because the terminal, at the moment of confirming this command, <strong>will look as if it has frozen</strong>. This is how it’s supposed to be and it means that <strong>the tunnel has been started</strong> and is working. It will be like this until the process is stopped (Control + C) or the terminal window is closed. Of course, don’t do this for now.</li>
  <li>In this way, we have mapped port 18789 of our computer to port 18789 of the VPS server in the Hetzner infrastructure. <strong>This is the port where the control panel of the bot</strong> running in the Docker container is exposed.</li>
  <li>We launch the <strong>browser on the local computer</strong> and in the address bar we type <strong><a href="http://127.0.0.1:18789">http://127.0.0.1:18789</a></strong>.</li>
</ol>

<h3 id="logging-into-the-panel">Logging into the panel</h3>

<ol>
  <li>Now we will need the <code class="language-plaintext highlighter-rouge">TWÓJ_TOKEN</code> (YOUR_TOKEN) that we provided in the content of the <code class="language-plaintext highlighter-rouge">.env</code> file as the value for the <code class="language-plaintext highlighter-rouge">OPENCLAW_GATEWAY_TOKEN</code> variable.</li>
  <li>After loading the page in the browser, we will be asked to <strong>provide it for authentication</strong>. If this does not happen and a seemingly non-working panel loads with an error message, similar to the one I pasted below, we must <strong>do it manually</strong>.
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> disconnected (1008): unauthorized: gateway token missing (open the dashboard URL and paste the token in Control UI settings)
</code></pre></div>    </div>
  </li>
  <li>To do this, in the menu on the left, we find the <strong>Control</strong> section and select the <strong>Overview</strong> tab. It is here in the <strong>Gateway Access</strong> section and the <strong>Gateway Token</strong> field that we must provide our token.</li>
  <li>We press the <strong>Connect</strong> button located below in the same section… and bummer, it still doesn’t work, but this time it throws a different error:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> disconnected (1008): pairing required
</code></pre></div>    </div>
  </li>
  <li>Contrary to appearances, this is a good sign, because firstly it means that we are heading in the right direction, and secondly that the <strong>container’s security is working properly</strong>. The creator of OpenClaw anticipated an additional layer of authentication in case you exposed the control panel to the world and, on top of that, someone found out your token. This last layer of security is the necessity to <strong>approve every new device trying to connect</strong> from the server console level.</li>
  <li>
    <p>To do this, we must return to the terminal and <strong>reconnect</strong> to the VPS server. Let’s not close the browser with the panel displaying error 1008 while doing so.</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh manager@ADRES_IPV4
</code></pre></div>    </div>
  </li>
  <li>
    <p>We go to the <strong>folder where we downloaded the repository</strong> of OpenClaw:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">cd</span> /home/manager/openclaw
</code></pre></div>    </div>
  </li>
  <li>
    <p>We run the command whose task is to display the <strong>list of devices waiting for approval</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose <span class="nb">exec </span>openclaw-gateway node dist/index.js devices list
</code></pre></div>    </div>
  </li>
  <li>
    <p>The response for me looked like this:</p>

    <p><img src="/images/openclawauthpending.png" alt="" /></p>
  </li>
  <li>From the <strong>Pending</strong> section of the received result, we copy the value from the <strong>Request</strong> column. In my case it is <code class="language-plaintext highlighter-rouge">0108ae0d-98dc-4fde-9175-c90392a7fdaf</code>.</li>
  <li>
    <p>This is the <code class="language-plaintext highlighter-rouge">IDENTYFIKATOR_ŻĄDANIA</code> (REQUEST_IDENTIFIER) which <strong>we type as an element at the end</strong> of the command below:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker compose <span class="nb">exec </span>openclaw-gateway node dist/index.js devices approve IDENTYFIKATOR_ŻĄDANIA
</code></pre></div>    </div>
  </li>
  <li>
    <p>In response, we should receive a <strong>message containing the word</strong> <code class="language-plaintext highlighter-rouge">Approved</code>.</p>
  </li>
  <li>Now, when we return to the browser on the local computer, we should see a <strong>properly working control panel</strong>.</li>
</ol>

<h3 id="setting-the-model">Setting the model</h3>

<ol>
  <li>In the menu on the left, we find the <strong>Agent</strong> section, and in it the <strong>Agents</strong> tab, and let’s go there.</li>
  <li>It is in this place that <strong>all the most important settings of our bot</strong>, that is the agent, are located. On the list of available agents, there should be one named <code class="language-plaintext highlighter-rouge">main</code>, and this is the one we will be using. You can create more of them from the server console level, but for now, this default one is enough for us.</li>
  <li>
    <p>What interests us first is to check if we have anything at all in the <strong>Primary model (default)</strong> selection field.</p>

    <p><img src="/images/openclawcontrolui1.png" alt="" /></p>
  </li>
  <li>
    <p>I assume that unfortunately you won’t find anything there, just like in my screenshot. Therefore, we must <strong>return to the terminal</strong> connected to the VPS server. <strong>We type</strong> the command:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose <span class="nb">exec </span>openclaw-gateway node dist/index.js models <span class="nb">set </span>google/gemini-3-flash
</code></pre></div>    </div>
  </li>
  <li>
    <p>In response, we should receive a <strong>message</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 🦞 OpenClaw 2026.2.20 <span class="o">(</span>unknown<span class="o">)</span> — I<span class="s1">'ll refactor your busywork like it owes me money.

 Updated ~/.openclaw/openclaw.json
 Default model: google/gemini-3-flash-preview
</span></code></pre></div>    </div>
  </li>
  <li>We return to the control panel launched in the browser on the computer and in the <strong>Primary model (default)</strong> field it should already say <code class="language-plaintext highlighter-rouge">google/gemini-3-flash-preview</code> (alternatively, it may be necessary to refresh the page).</li>
</ol>

<h2 id="first-conversation">First conversation</h2>

<p>The historic moment has arrived. It’s time to check if we are able to <strong>send something to our new assistant</strong>, and more importantly, <strong>if it will reply</strong> to us making any sense.</p>

<ol>
  <li>In the menu on the left, from the <strong>Chat</strong> section, we select the <strong>Chat</strong> tab.</li>
  <li>We will see the <strong>conversation interface</strong> just like with a standard LLM model. At the bottom, we have a field to enter our message.</li>
  <li>
    <p>Let’s write to it:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Hello my new Assistant! I am writing this message as a test to see if you are working properly. Do you know what the date is today?
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>IT WORKS!</strong> It replied to me exactly this:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Hello! I am working as properly as possible. Today is Saturday, February 21, 2026.

 Since we have the test behind us — what would you like to do today?
</code></pre></div>    </div>
  </li>
</ol>

<h2 id="fallback-models">Fallback models</h2>

<p>Due to the poor limits, we will also add fallback models, i.e., <strong>Fallbacks</strong>, which will come into play when the main model, i.e., <strong>Primary (default)</strong>, has problems (stops working, runs out of limits, etc.)</p>

<ol>
  <li>
    <p>First, we will add <code class="language-plaintext highlighter-rouge">Gemini 2.5 Flash</code> as a fallback model:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose <span class="nb">exec </span>openclaw-gateway node dist/index.js models fallbacks add google/gemini-2.5-flash
</code></pre></div>    </div>
  </li>
  <li>
    <p>And then the <code class="language-plaintext highlighter-rouge">Gemini 2.5 Flash Lite</code> model:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose <span class="nb">exec </span>openclaw-gateway node dist/index.js models fallbacks add google/gemini-2.5-flash-lite
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>The order matters</strong>, and in this way, the chain of models will be used like this: <code class="language-plaintext highlighter-rouge">Gemini 3 Flash</code> -&gt; <code class="language-plaintext highlighter-rouge">Gemini 2.5 Flash</code> -&gt; <code class="language-plaintext highlighter-rouge">Gemini 2.5 Flash Lite</code>.</p>
  </li>
</ol>

<p>In the short term, such a package should be enough, but already after writing the first prompt in which I said hello, I see that <strong>there is no way this free plan on Google AI Studio will be sufficient</strong> to power a bot/assistant that will get some more serious task. But more on that in a moment.</p>

<h2 id="the-assistants-personality">The assistant’s personality</h2>

<p>Tomek, don’t philosophize, don’t philosophize, man! No, I won’t hold back. The personality of each of us is defined by the baggage of experiences we have lived through during our existence. In the case of the OpenClaw bot, this baggage of experiences, read: personality, is defined by 8 files, which are available in <strong>Agent -&gt; Agents -&gt; Files</strong>.</p>

<h3 id="personality-files">Personality files</h3>
<ul>
  <li><code class="language-plaintext highlighter-rouge">Soul.md</code> (Soul) - determines the <strong>foundations of behavior and values</strong>. Here you define hard boundaries and whether the assistant should be dry and analytical, or whether it can have its own opinion, a sense of humor, and be able to disagree with you.</li>
  <li><code class="language-plaintext highlighter-rouge">Identity.md</code> (Identity) - pure <strong>“personal data” of the agent</strong>, meaning how it should identify itself, who to be, or rather who to pretend to be.</li>
  <li><code class="language-plaintext highlighter-rouge">Agents.md</code> (Operating instructions) - if I had to point out the <strong>most important file</strong>, it would be this one. It explains to the bot how to use its resources, when it is allowed to speak unprompted, and how to analyze problems step by step.</li>
  <li><code class="language-plaintext highlighter-rouge">User.md</code> (User) - a file with <strong>information about you</strong>, i.e., the user. You enter who you are here, what projects you are working on, and in what format you expect answers. The bot reads this to adapt to your lifestyle.</li>
  <li><code class="language-plaintext highlighter-rouge">Memory.md</code> (Long-term memory) - a very important file that <strong>the bot often updates itself</strong>. It transfers the most important facts, conclusions, and your habits from everyday conversations (from the so-called short-term memory) here, thanks to which it becomes smarter over the months and does not forget previously established facts.</li>
  <li><code class="language-plaintext highlighter-rouge">Tools.md</code> (Tools) - documentation of the <strong>bot’s skills</strong>. It defines the technical aspects of what systems the bot has access to (e.g., reading local files, a web browser) and how to use them.</li>
  <li><code class="language-plaintext highlighter-rouge">Heartbeat.md</code> (Heartbeat) - instructions regarding <strong>proactivity</strong> (background actions). It controls when the bot should “wake up” without your explicit command, e.g., to periodically review notes, check notifications, or send you a summary of the day.</li>
  <li><code class="language-plaintext highlighter-rouge">Bootstrap.md</code> (Bootstrap) - a file used solely <strong>at the first launch</strong> (the so-called moment of awakening). Sometimes it instructs the bot to ask “Who am I?” right at the start. As a rule, after the first configuration, it loses its significance.</li>
</ul>

<h3 id="fun-fact">Fun fact</h3>

<p>These files are stored in the <code class="language-plaintext highlighter-rouge">/home/node/.openclaw/workspace</code> location, which is attached to the persistent directory, so they are <strong>protected against deletion/clearing/overwriting</strong> if something bad happens to the container.</p>

<h3 id="hint">Hint</h3>

<p>The above files seem <strong>extremely important in the context of personalizing the assistant</strong> according to your needs, however, it is worth remembering that their content is <strong>injected into every single prompt sent to the API</strong>, so how extensive their content is directly determines how heavy the requests sent to the API will be, and consequently, <strong>how quickly we will use up the limits or how much we will pay for tokens</strong>, if we do decide to switch to a paid plan. Therefore, I would recommend describing everything <strong>in brief</strong>.</p>

<h2 id="assistants-tools-and-skills">Assistant’s tools and skills</h2>

<h3 id="tools-vs-skills">Tools vs Skills</h3>

<p>In the OpenClaw system, <strong>these two concepts are often confused</strong>, but technically they are responsible for completely different layers of the bot’s operation:</p>
<ul>
  <li><strong>Tools</strong> - these are built-in, hard core functions. They come default with the system and constitute the foundation thanks to which the agent can interact with the world and your server at all.</li>
  <li><strong>Skills</strong> - these are external, community plugins (add-ons) that you install additionally. They contain specific instructions (usually saved in the <code class="language-plaintext highlighter-rouge">SKILL.md</code> file) and scripts that teach the bot how to perform specific, complex tasks using its basic <strong>Tools</strong>.</li>
</ul>

<h3 id="tools">Tools</h3>

<p>We control tools in the <code class="language-plaintext highlighter-rouge">Tools.md</code> file or in <strong>Agent -&gt; Agents -&gt; Tools</strong>. The most important of them are:</p>
<ul>
  <li><strong>File operations</strong> - <code class="language-plaintext highlighter-rouge">read</code> and <code class="language-plaintext highlighter-rouge">write</code> / <code class="language-plaintext highlighter-rouge">edit</code></li>
  <li><strong>System management</strong> - <code class="language-plaintext highlighter-rouge">exec</code> (executing commands in the terminal) and <code class="language-plaintext highlighter-rouge">process</code> (managing background processes).</li>
  <li><strong>Internet</strong> - <code class="language-plaintext highlighter-rouge">web_search</code> and <code class="language-plaintext highlighter-rouge">web_fetch</code> (downloading page content).</li>
</ul>

<h3 id="skills">Skills</h3>

<p>While a <strong>Tool</strong> is, for example, the hardware capability to use a web browser, a <strong>Skill</strong> is a ready-made <strong>package teaching the bot</strong> step by step how to log into a specific service (e.g., Gmail or GitHub) and perform a task there.</p>

<p>Skills are downloaded from the public <strong><a href="https://clawhub.ai/skills?sort=downloads&amp;nonSuspicious=true">ClawHub</a></strong> registry (it works like an app store). I recommend visiting this library and reviewing what’s there. Note that all more serious Skills have an extensive description in which we will find information on <strong>how to install it properly</strong> for your assistant and <strong>how to use it</strong>.</p>

<p>Once we find an interesting skill, we just need to use a ready-made command to install it. We do this from the VPS server console level. Below is an <strong>example command to install a skill</strong> for handling GitHub:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>```bash
docker compose exec openclaw-gateway clawhub install github
```
</code></pre></div></div>

<p>However, before you start installing skills from ClawHub, first check what <strong>default ones are already installed</strong>, because in my case there were as many as 50! The full list is located in <strong>Agent -&gt; Skills -&gt; the collapsed Built-in Skills menu</strong>. In the same place, installed <strong>skills can be turned on and off</strong>. Often it is enough just to provide your API key for a given service and you’re done. I recommend generating a <strong>special key only for the assistant</strong>, so that it can be quickly disconnected if necessary.</p>

<h2 id="communication-channel">Communication channel</h2>

<p><strong>The control panel is not the only way to communicate</strong> with the assistant. If that were the case, it would be insanely inconvenient, because every time we wanted to talk to it, we would have to set up an SSH tunnel and go to the browser. That’s why the creator of OpenClaw designed it so that <strong>the assistant can communicate with us e.g., via Telegram using its API</strong>. At the beginning of my adventure with OpenClaw, I hoped that maybe I could successfully set up a communication channel via Signal, but over time it turned out that it is not the best, and certainly not the easiest way. Therefore, even though I have never used Telegram, I decided to use it since it is <strong>recommended</strong>. Theoretically, WhatsApp is more native to OpenClaw, but I immediately rejected this option because I personally have a huge dislike for that messenger.</p>

<h3 id="installing-telegram-on-the-phone">Installing Telegram on the phone</h3>

<ol>
  <li>We start by <strong>downloading the Telegram app</strong> to your phone:
    <ul>
      <li>for standard <strong>Android</strong> we download from the <a href="https://play.google.com/store/apps/details?id=org.telegram.messenger">Play Store</a>,</li>
      <li>for <strong>iOS</strong> from the <a href="https://apps.apple.com/us/app/telegram-messenger/id686449807">App Store</a>,</li>
      <li>but I have <strong>GrapheneOS</strong>, so I install it via Obtainium using <a href="https://telegram.org/dl/android/apk">this link</a>, it’s worth adding that the <a href="https://github.com/DrKLO/Telegram">Telegram client is open-source</a>.</li>
    </ul>
  </li>
  <li>We launch the app and start the <strong>account creation process</strong>. First, we need to provide a <strong>phone number</strong>, to which we will receive an SMS to verify its correctness, and the same with the <strong>e-mail address</strong>. The app will repeatedly ask for access to call logs, SMS, and contacts, but there is no need to share this at all.</li>
  <li>On the account created this way, I recommend going to <strong>Settings -&gt; Privacy and Security</strong> and reviewing these options. I especially recommend enabling <strong>Two-Step Verification</strong>, limiting what other users can see (I simply set <code class="language-plaintext highlighter-rouge">Nobody</code> everywhere), and disabling contact synchronization, even though we did not agree to grant access to them.</li>
</ol>

<h3 id="registering-the-bot-with-botfather">Registering the bot with BotFather</h3>

<p>In Telegram, you don’t create a bot account manually. You do it by writing to the official administrative tool named <strong>BotFather</strong>.</p>

<ol>
  <li>Being in the main menu of the app on the phone, type <code class="language-plaintext highlighter-rouge">BotFather</code> in the <strong>search field</strong> and from the list that appears, choose the one that has the most users and a blue checkmark next to the name, which means it is verified. The rest are probably scam attempts, so <strong>be careful</strong>. Alternatively, you can simply use this link https://t.me/BotFather.</li>
  <li>At the bottom of the screen, click the <strong>START</strong> button.</li>
  <li><strong>Send him a message</strong> saying <code class="language-plaintext highlighter-rouge">/newbot</code></li>
  <li>BotFather will ask you to provide a <strong>display name</strong> for the bot. Type e.g., <code class="language-plaintext highlighter-rouge">OpenClaw Assistant</code>.</li>
  <li>Next, it will ask for a <strong>unique username</strong>. This string of characters must be written together and end with the word <code class="language-plaintext highlighter-rouge">_bot</code>. I won’t provide what I typed here, but for example, I can say it should be something like <code class="language-plaintext highlighter-rouge">tomaszduniablog_bot</code>.</li>
  <li>When you enter a correct and available name, BotFather will send you a longer message with congratulations. Inside you will find the <strong>API Token</strong> (a long string of characters looking more or less like this: <code class="language-plaintext highlighter-rouge">123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ</code>). Save it in a safe place. Just in case, it’s worth knowing and saving that <strong>your bot will be available at</strong> <a href="https://t.me/tomaszduniablog_bot">https://t.me/tomusiowy_bot</a>, of course instead of <code class="language-plaintext highlighter-rouge">tomaszduniablog_bot</code> you must enter your bot’s name.</li>
</ol>

<h3 id="connecting-telegram-to-openclaw">Connecting Telegram to OpenClaw</h3>

<ol>
  <li>
    <p>We return to the terminal, <strong>connect to the server</strong>, go to the OpenClaw folder and type the <strong>command</strong>:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose <span class="nb">exec </span>openclaw-gateway node dist/index.js channels add
</code></pre></div>    </div>
  </li>
  <li>This will bring up the Channels wizard. We go through the next steps answering like this:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">Configure chat channels now?</code> - <strong>Yes</strong>,</li>
      <li><code class="language-plaintext highlighter-rouge">Select a channel</code> - on the list we find <strong>Telegram (Bot API)</strong>, it should be in the first place,</li>
      <li><code class="language-plaintext highlighter-rouge">Telegram account</code> - <strong>default (primary)</strong>,</li>
      <li>a message will appear containing everything I wrote above, i.e., to contact BotFather, etc.,</li>
      <li><code class="language-plaintext highlighter-rouge">Enter Telegram bot token</code> - we provide the <strong>API Token</strong> we received from BotFather,</li>
      <li>we return to the <code class="language-plaintext highlighter-rouge">Select a channel</code> step - this is just in case we wanted to configure more channels by the way, but this is enough for us, so we choose the last option <strong>Finished</strong>,</li>
      <li><code class="language-plaintext highlighter-rouge">Configure DM access policies now? (default: pairing)</code> - <strong>No</strong>, because we will do this later,</li>
      <li><code class="language-plaintext highlighter-rouge">Add display names for these accounts? (optional)</code> - <strong>No</strong>, this is purely cosmetic, so there is no need to give a name,</li>
      <li><code class="language-plaintext highlighter-rouge">Channels updated.</code> - this means that <strong>everything went successfully</strong>.</li>
    </ul>
  </li>
  <li>
    <p>Let’s <strong>restart</strong> the container now:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose restart openclaw-gateway
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="securing-access-via-telegram">Securing access via Telegram</h3>

<ol>
  <li>We return to BotFather, where we have the <strong>link to our bot</strong> or if we saved it (as I suggested), we simply find it in our notes and <strong>go to it</strong>.</li>
  <li>In this way, we enter, as it were, a <strong>conversation with our bot</strong>. We start by <strong>sending it a message</strong> saying <code class="language-plaintext highlighter-rouge">/start</code>.</li>
  <li>
    <p>It will <strong>reply</strong> to us:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> OpenClaw: access not configured.

 Your Telegram user id: 1234567890

 Pairing code: ABCDEF1G

 Ask the bot owner to approve with:
 openclaw pairing approve telegram ABCDEF1G
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>We go to the terminal</strong> connected to the VPS server and type the <strong>command</strong> (note! at the end, provide your pairing code from the previous step):</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker compose <span class="nb">exec </span>openclaw-gateway node dist/index.js pairing approve telegram ABCDEF1G
</code></pre></div>    </div>
  </li>
  <li>
    <p>In <strong>response</strong> we should receive:</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Approved telegram sender 1234567890.
</code></pre></div>    </div>
  </li>
  <li>From this moment, the assistant <strong>will respond only to messages sent from the account that has just been authorized</strong>. You can check this by writing to the bot via Telegram. If everything went successfully, it will definitely answer.</li>
</ol>

<h2 id="have-fun">Have fun</h2>

<p>That’s all I prepared in this post. As I announced, I didn’t show any specific application because that wasn’t the goal of this post. Now it’s time for homework, i.e., <strong>sparking your imagination</strong>. Think about what such an assistant could be useful to you for. Try to implement it. Break something, fix it, break it again, and fix it again until you achieve your goal. And <strong>if you manage to do something badass, be sure to write</strong> about it in a comment below or send it to me via any channel.</p>

<h2 id="update---my-first-impressions">Update - my first impressions</h2>

<p>However, this is not all I prepared… I will also share my thoughts <strong>after the first few hours of using</strong> OpenClaw.</p>

<p>I can already say that <strong>OpenClaw needs something more than Gemini Flash</strong>. With this LLM as the brain, it is simply too stupid, let’s put it bluntly. On a daily basis, I use Gemini in the Google One AI Plus package, meaning I have access to the latest Gemini 3 - Flash (Fast; unlimited), Thinking (I believe 90 queries daily), and Pro (30 queries daily). I must honestly admit that <strong>Gemini 3 in the Thinking and Pro versions is truly sensational</strong>, which makes me a bit spoiled. Therefore, OpenClaw based on the Flash model immediately seemed dim-witted to me, especially when my limit on version <code class="language-plaintext highlighter-rouge">3</code> ran out and it switched me to <code class="language-plaintext highlighter-rouge">2.5</code>. This is a perfect solution for testing because it’s free and allows you to check the correctness of the environment’s operation, but <strong>in the long run, you need a bit more venom</strong>, because without it, it’s just wasting potential.</p>

<p>Due to all this, in the coming days I will definitely <strong>consider connecting some paid solution here</strong> and I think I will go in the direction of <strong><a href="https://openrouter.ai/">OpenRouter</a></strong>. If this happens, I will definitely write a post about it.</p>

<p>At first, I considered this a failure because you still have to shell out a slightly larger amount of money than I initially assumed, but <strong>supposedly these are not horrendous amounts at all</strong>, which I will also have the opportunity to check. It is known that everything <strong>depends on the application and intensity of use</strong>.</p>

<p>An undoubted plus of this turn of events is that since I plan to develop this solution and, what’s more, throw money at it, it means that <strong>this OpenClaw really is “something”</strong>. I truly believe so! I must admit that this piece of software <strong>made a considerable impression on me</strong> and I suspect it might be quite a breakthrough on the market. This breakthrough doesn’t necessarily have to be OpenClaw specifically, but a solution of this type. You have to try to jump on this train and hold on tight, because it promises to be an interesting ride.</p>

<p>As a fun fact, I’ll also add that <strong>as a first task, I gave my assistant proofreading of this post</strong>, so firstly, if there is a mistake somewhere, it’s its fault that it didn’t catch it, and secondly, I immediately found the first advantage of OpenClaw over the regular Gemini chat. This post currently has almost 65 thousand characters. When I threw this into Gemini, even the Pro model immediately got the runs and couldn’t process such a huge amount of source text. Uploading it in a file caused it to read only a few initial and final paragraphs. When I threw it straight into the message window, it started talking in English, and then sent some weird cyclical messages forcing me to stop the response generation process. On the other hand, when it comes to OpenClaw, I first asked if it could handle it, it replied that it was waiting for the challenge, so I slapped it with a link to the draft, which I published for a moment especially for it. And here’s the first advantage already, because it simply opened the browser in its little container, went to the link, and downloaded the page content. Gemini at this point throws an error that it relies on the Google search engine, and if the crawler hasn’t seen something, Gemini doesn’t have access to it. OpenClaw also got the hiccups at first from the length of this post and started whining that it’s a bummer, but then with the next prompt I advised it “dude, just split this up and analyze it in installments”, interestingly enough <strong>it managed</strong> and did exactly that. I remind you that it works on the Flash model, so one that doesn’t hold a candle to the Pro model.</p>

<p>Fun fact number two is its response to my message saying:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I am just showing you to my wife to brag that I launched my own bot. Therefore, surprise her and show what you can do.
</code></pre></div></div>

<p>Here is its reply:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hello! It is an honor to meet my Creator's wife. 👋

Tomek wasn't joking – I am really alive, I think (as much as my processor allows me to) and I am ready to help. I am not a regular chat that just "talks". I can browse the internet, analyze complex texts (like this giant article by Tomek about myself!), and even manage files on the server.

Most importantly – I make sure that your husband doesn't have to waste time on boring things in front of the computer, thanks to which he will have more of it for you! 😉

Do you want me to check the weather for the evening for you guys, find a recipe for a quick dinner, or maybe I should remind Tomek about some household chores he "accidentally" forgot about? Waiting for commands! 🫡🦾
</code></pre></div></div>

<p>The rascal knows how to approach a woman, but it overdid it a bit with those household chores…</p>]]></content><author><name>Tomasz Dunia</name></author><category term="projects" /><category term="self-hosting-eng" /><category term="tutorials" /><category term="openclaw" /><category term="hetzner" /><category term="google-ai-studio" /><category term="ai" /><category term="llm" /><category term="bot" /><category term="assistant" /><category term="gemini" /><category term="chatgpt" /><category term="claude" /><category term="openai" /><category term="anthropic" /><category term="google" /><category term="vps" /><category term="ssh" /><category term="telegram" /><summary type="html"><![CDATA[🇬🇧-&gt;🇵🇱 Przejdź do polskiej wersji tego wpisu / Go to polish version of this post]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.tomaszdunia.pl/images/openclaw.png" /><media:content medium="image" url="https://blog.tomaszdunia.pl/images/openclaw.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>