
OpenCode to agent kodu open source (Anomaly, licencja MIT), który działa w terminalu, jako rozszerzenie edytora albo aplikacja desktopowa. Zainstalowany bez zostawiania śladu w systemie, działa od pierwszej komendy dzięki darmowemu modelowi i obsługuje serwery MCP oraz format skilli SKILL.md, łącznie z tymi już zainstalowanymi dla innych agentów, jeśli nie są izolowane. Modele lokalne przechodzą przez generycznego dostawcę kompatybilnego z OpenAI, nie przez dedykowaną integrację Ollama.
Agent kodu open source obiecuje, że nie zamknie Cię u jednego wydawcy. Model się wybiera, kod zostaje na Twojej maszynie, licencja jest permisywna. Zainstalowałem OpenCode, nie dotykając systemu ani nie wpisując ani jednego identyfikatora, zanim odkryłem, że zapomniany eksport zmiennej wystarczy, żeby kazać mu załadować skille już zainstalowane dla innych narzędzi.
OpenCode, trzy interfejsy na licencji MIT
OpenCode jest rozwijany przez Anomaly i publikowany na licencji MIT w repozytorium anomalyco/opencode, które pokazywało około 206 000 gwiazdek 7 września 2026. Narzędzie przedstawia się jako „an open source agent that helps you write code in your terminal, IDE, or desktop”. Występuje w trzech interfejsach: kliencie terminalowym (TUI), rozszerzeniu do edytora i aplikacji desktopowej w becie na macOS, Windows i Linux.
LSP w zasadzie ładuje się automatycznie zależnie od wykrytego języka, a przez Models.dev i AI SDK obsługiwanych jest ponad 75 dostawców modeli, od płatnego API po model lokalny. W moim mini-projekcie testowym log zanotował jednak „all LSPs are disabled”: wykrycie języka nie wystarcza, odpowiedni serwer musi być obecny, żeby funkcja się uruchomiła. Strona zresztą zapewnia „OpenCode does not store any of your code or context data”. Nic domyślnie nie trafia na serwery Anomaly, ale wszystko zostaje w lokalnej bazie SQLite, jak pokazuje kolejna sekcja.
OpenCode dołącza do już długiej listy agentów w linii poleceń: nasz przegląd agentów kodu porównuje ich wszystkich. Ten artykuł skupia się na tym, co odkrywa się, instalując i rozkładając tego jednego na części, kawałek po kawałku.
Zainstalować OpenCode, nie zostawiając niczego w systemie
Pakiet npm opencode-ai instaluje skompilowany plik binarny (opencode-darwin-arm64 na tym Macu) za plikiem wykonywalnym opencode.exe. Żeby niczego nie zostawić w globalnych lokalizacjach, kierunek: tymczasowy prefiks laboratorium, z lokalnym cache npm i izolowanym HOME dla wszystkich poleceń, które następują:
mkdir -p docker/articles/2026-09-07/lab/opencode-agent-code-open-source/{prefix,home,projet-demo}
cd docker/articles/2026-09-07/lab/opencode-agent-code-open-source
npm install opencode-ai --prefix ./prefix --cache ./prefix/.npm-cache
export HOME="$PWD/home"
./prefix/node_modules/.bin/opencode --versionKomenda zwraca 1.18.29, opublikowaną 4 września 2026 o 23:47 według wydań na GitHubie, trzy dni przed tym testem. Piąta wersja w osiem dni: od 1.18.25 do 1.18.29 między 28 sierpnia a 4 września. Rejestr npm potwierdza, że to najnowsza dostępna wersja. Dokumentacja proponuje też skrypt curl -fsSL https://opencode.ai/install | bash oraz pakiety Homebrew, Scoop albo pacman, zachowałem npm, żeby cała instalacja zmieściła się w folderze, który usuwam na koniec.
Instalacja niekoniecznie kończy się na tym. Po uruchomieniu kilku poleceń z poziomu projektu, OpenCode samodzielnie zainstalował 54 MB zależności w .opencode/node_modules, bez pytania o zgodę: własne SDK pluginów, bibliotekę effect, i bardziej zaskakującą obecność, kubernetes-types. .opencode/.gitignore był już gotowy, żeby wykluczyć je ze śledzenia przez Git.
Gdzie OpenCode czyta swoją konfigurację
Gdy HOME jest już izolowany, komenda opencode debug paths, podnarzędzie diagnostyczne nieobecne w głównym menu, pokazuje strukturę w stylu XDG, którą OpenCode zbudował sobie w tym fałszywym katalogu domowym (ścieżki skrócone dla czytelności):
opencode debug paths
home .../lab/opencode-agent-code-open-source/home
config .../home/.config/opencode
data .../home/.local/share/opencode
cache .../home/.cache/opencode
state .../home/.local/state/opencode
tmp /var/folders/.../T/opencodePlik opencode.log zapisywany w data/log podaje dokładną kolejność odczytu przy starcie: najpierw folder konfiguracji globalnej (opencode.json, .jsonc), potem, zaczynając od bieżącego folderu, opencode.json i .opencode/opencode.json projektu. Skill wbudowany w plik binarny, czytelny przez opencode debug skill, dokumentuje tę samą hierarchię, z tabelą, którą warto przepisać:
| Zakres | Ścieżka |
|---|---|
| Konfiguracja projektu | ./opencode.json, ./opencode.jsonc albo .opencode/opencode.json (szukana, cofając się od bieżącego folderu do korzenia repozytorium Git) |
| Konfiguracja globalna | ~/.config/opencode/opencode.json albo .jsonc, nie ~/.opencode/ |
| Skille projektu | .opencode/skill(s)/<nazwa>/SKILL.md |
| Skille globalne | ~/.config/opencode/skill(s)/<nazwa>/SKILL.md |
| Skille zewnętrzne (ładowane automatycznie) | ~/.claude/skills/<nazwa>/SKILL.md, ~/.agents/skills/<nazwa>/SKILL.md |
Konfiguracje z każdego zakresu są scalane (deep-merge), projekt bierze górę nad globalną. Ostatnia linia tabeli sięga najdalej. OpenCode czyta, bez dodatkowej deklaracji, skille już zainstalowane dla Claude Code i dla innych agentów zgodnych z otwartym standardem Agent Skills, opisanym w naszym przewodniku po SKILL.md.
Skille: jak daleko sięga automatyczne wykrywanie?
Żeby zweryfikować to, co mówi wbudowana dokumentacja, dodałem dwa skille-wabiki bezpośrednio w fałszywym HOME, dokładnie tam, gdzie OpenCode mówi, że ich szuka, zanim ponownie uruchomiłem tę samą diagnostykę:
mkdir -p home/.claude/skills/decoy-claude home/.agents/skills/decoy-agents
# minimalny SKILL.md (frontmatter name + description) w każdym folderze
opencode debug skillWynik: cztery wykryte skille, skill wbudowany, skill projektu, i oba wabiki, każdy z pełną ścieżką w home/.claude/skills/… i home/.agents/skills/…. OpenCode po prostu szanuje zmienną HOME, którą mu podajemy, tyle że patrzy szerzej niż tylko na swój własny folder konfiguracji.
Bez ponownie wyeksportowanego HOME w komendzie ta sama lista wraca do prawdziwego katalogu domowego maszyny i wyciąga 120 skilli, tych naprawdę zainstalowanych dla Claude Code i dla innych agentów. Żadnej ucieczki z sandboksa w tym nie ma. Jedna komenda bez jawnego HOME wystarczy, żeby przykleić z powrotem test, który wydawał się izolowany, do Twojego prawdziwego katalogu domowego, a więc do skilli już zainstalowanych dla innych narzędzi, nigdy niezadeklarowanych w projekcie. Sama komenda jest wymowna: żaden opencode skill list nie istnieje na pierwszym poziomie, trzeba przejść przez opencode debug skill, narzędzie diagnostyczne.
MCP: skonfigurować i odpytać lokalny serwer
Plik konfiguracji projektu deklaruje lokalny serwer MCP, powiązane uprawnienia, i ogranicza dostęp do narzędzia dla agenta plan:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"slug": {
"type": "local",
"command": ["node", "./mcp/serveur.mjs"],
"enabled": true
}
},
"permission": {
"edit": { "*": "ask", "docs/**": "allow" },
"bash": { "*": "ask", "git status": "allow", "git diff *": "allow", "rm *": "deny" },
"webfetch": "deny",
"skill": { "*": "allow" }
},
"agent": {
"plan": { "tools": { "slug_*": false } }
}
}Serwer, mcp/serveur.mjs, to samodzielny skrypt Node liczący około czterdziestu linii, który mówi JSON-RPC 2.0 na wejściu standardowym i udostępnia jedno narzędzie, slug_fr:
const TOOLS = [{
name: "slug_fr",
description: "Transforme un titre francais en slug d'URL (minuscules, sans accent).",
inputSchema: {
type: "object",
properties: { titre: { type: "string", description: "Le titre a convertir" } },
required: ["titre"]
}
}];
function slug(titre) {
return titre.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
}opencode mcp list potwierdza połączenie:
opencode mcp list
MCP Servers
slug connected
node ./mcp/serveur.mjs
1 server(s)Skill projektu, slug-gekkode, wyjaśnia regułę biznesową (maksymalnie pięć słów, bez przedimka) i odsyła do narzędzia. Jedno przejście przez opencode run uruchamia oba po kolei (wyjście oczyszczone z kodów kolorów i ikon, treść niezmieniona):
opencode run "Utilise la regle de slug du projet pour convertir ce titre : Les secrets d'une bonne architecture PHP"
> build - big-pickle
Skill "slug-gekkode"
slug_slug_fr {"titre":"Les secrets d'une bonne architecture PHP"}
Le slug genere par l'outil MCP est : les-secrets-d-une-bonne-architecture-php
Mais selon les regles du skill (max 5 mots, sans article ni preposition),
le slug correct est : secrets-bonne-architecture-phpWyświetlona nazwa narzędzia, slug_slug_fr, pokazuje konwencję nazewnictwa. OpenCode poprzedza każde narzędzie MCP nazwą serwera zadeklarowaną w konfiguracji (slug), doklejoną do nazwy udostępnianego narzędzia (slug_fr), stąd powtórzenie. Model wybrał skill na podstawie jego opisu, wywołał narzędzie, a potem przeliczył wynik ręcznie, żeby zachować regułę pięciu słów. Skill, który uzupełnia narzędzie zamiast je zastępować, zachowuje się dokładnie tak. Dla zdalnego serwera dokumentacja opisuje blok "type": "remote" z url i headers albo oauth, plus opencode mcp auth dla przepływu OAuth. Temat jest pogłębiony w naszym artykule o tworzeniu serwera MCP w PHP.
Agenty i uprawnienia, reguła po regule
opencode agent list pokazuje osiem agentów w tym projekcie: build (główny agent domyślny, szeroki dostęp), plan (główny, odczyt i planowanie), compaction, summary i title (wewnętrzne), explore i general (subagenty), i relecteur, zadeklarowany w .opencode/agents/relecteur.md:
---
description: Relit un article et signale les fautes, sans jamais modifier de fichier.
mode: subagent
temperature: 0.1
permission:
edit: deny
bash: deny
---
Vous relisez un article de blog en francais. Vous signalez les erreurs, vous ne corrigez rien.Każde uprawnienie przyjmuje allow, ask albo deny, według wzorca glob, przy czym wygrywa reguła najbardziej szczegółowa. Ustawienie dotyczy edit, bash, webfetch, skill, a nawet konkretnego narzędzia MCP jak slug_*. Agent plan tego projektu ilustruje tę zasadę: jego konfiguracja wyłącza narzędzie slug_* i pozwala na zapis tylko w .opencode/plans/*.md, nigdy w kodzie. W trybie nieinteraktywnym, bez terminala, żeby odpowiedzieć na pytanie, uprawnienie ask nie zostaje w oczekiwaniu: jest automatycznie odrzucane:
opencode run "Execute la commande shell : echo test-permission"
> build - big-pickle
! permission requested: bash (echo test-permission); auto-rejecting
Error: The user rejected permission to use this specific tool call.
$ echo $?
0Domyślne zachowanie jest więc zamknięte: bez ludzkiego nadzoru OpenCode kończy się niepowodzeniem, zamiast wykonać komendę niewyraźnie autoryzowaną. Kod wyjścia mimo niepowodzenia i tak pozostaje 0, pułapka dla tego, kto skryptuje na tym weryfikację. Temat uprawnień i sandboksa, wspólny dla wszystkich tych agentów, jest pogłębiony w naszym artykule o agentach kodu, sandboksie i uprawnieniach.
Modele: darmowa próba, i przypadek modeli lokalnych
Bez konta i klucza, opencode run "dis bonjour" działa od pierwszej komendy. Model używany domyślnie, big-pickle („stealth model” według jego karty), jest jednym z sześciu darmowych modeli OpenCode Zen, własnej bramki. Pozostałych pięć to MiMo-V2.5 Free, Ling 3.0 Flash Fin Free, dwa warianty Nemotron 3 i Muse Spark 1.3 Contributor Free. Lokalna baza SQLite (tabela message) zachowuje ślad wymiany. Tabele credential i account zostają przy zerze wierszy: dla tego modelu nie poproszono o żaden identyfikator ani go nie zapisano, a koszt w dzienniku sesji jest zerowy.
Markowy model z tego samego katalogu (GPT, Claude, Gemini, Grok, DeepSeek, Qwen…) wymaga konta OpenCode Zen i metody płatności. Rozliczenie idzie za token, od 0,20 $ do kilku dolarów za milion zależnie od modelu. Saldo doładowuje się automatycznie o 20 $, gdy tylko spadnie poniżej 5 $.
Dla modelu lokalnego weryfikacja jest prosta:
which ollama
# ollama not foundKatalog modeli zapisany w cache przez OpenCode oferuje tylko jednego dostawcę chmurowego, ollama-cloud (klucz OLLAMA_API_KEY), bez dedykowanego wpisu dla lokalnego Ollama. Dla lokalnego serwera, Ollama, llama.cpp albo LM Studio, dokumentacja opisuje generycznego dostawcę kompatybilnego z OpenAI, do zadeklarowania samodzielnie:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"ollama-local": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama (local)",
"options": { "baseURL": "http://127.0.0.1:11434/v1" },
"models": { "mon-modele": { "name": "Mon modele local" } }
}
}
}Port 11434 i natywne API (/api/generate, między innymi) są udokumentowane na docs.ollama.com. Zgodność z OpenAI, której wymaga @ai-sdk/openai-compatible, sprowadza się do dwóch wywołań, sprawdzonych na Ollamie 0.34.0 uruchomionej w kontenerze:
curl -s http://127.0.0.1:11434/v1/models
# {"object":"list","data":[{"id":"qwen2.5:0.5b","object":"model",
# "created":1789038968,"owned_by":"library"}]}
curl -s http://127.0.0.1:11434/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"qwen2.5:0.5b","messages":[{"role":"user",
"content":"Réponds par le seul mot OK."}],"max_tokens":5}'
# {"id":"chatcmpl-704","object":"chat.completion","model":"qwen2.5:0.5b",
# "choices":[{"index":0,"message":{"role":"assistant","content":"OK."},
# "finish_reason":"stop"}],
# "usage":{"prompt_tokens":38,"completion_tokens":3,"total_tokens":41}}Forma jest dokładnie ta, której oczekuje SDK: object: "list" na katalogu, pełny obiekt chat.completion z choices, finish_reason i usage na uzupełnieniu. Nieznany model odpowiada 404 z obiektem błędu OpenAI, a nagłówek Authorization jest akceptowany niezależnie od wartości: pole apiKey dostawcy może zawierać cokolwiek.
Czego brakuje, z tej perspektywy
Pełny przegląd agentów kodu w linii poleceń, mocne i słabe strony wobec Claude Code, Codex, Gemini CLI i innych, jest omówiony osobno w naszym dedykowanym porównaniu. Lista skilli i rozwiązana konfiguracja są dostępne tylko przez komendy diagnostyczne, debug skill i debug config. Obie są nieobecne w głównym menu: przydatne, gdy się je już zna, ale niezbyt łatwe do odkrycia. Lokalne przechowywanie jest jak najbardziej rzeczywiste: sesja, wiadomości i wywołania narzędzi żyją w bazie SQLite na Twoim dysku, więc „żadne dane nie są wysyłane na serwery Anomaly” nie oznacza „nic nie jest zapisywane”. A darmowy dostęp kończy się na modelu własnym: przy pierwszym markowym modelu wraca konto i karta bankowa, które znalazłoby się gdziekolwiek indziej.
Co warto zapamiętać
- OpenCode (Anomaly, licencja MIT) instaluje się, nie zostawiając niczego w systemie, przez
npm install opencode-ai --prefixi izolowanyHOME, testowana wersja: 1.18.29. - Konfiguracja czyta się na trzech scalonych poziomach: projekt (cofając się aż do korzenia Git), globalny (
~/.config/opencode, nigdy~/.opencode), i skille zewnętrzne ładowane automatycznie z~/.claude/skillsi~/.agents/skills. - Izolowanie
HOMEdziała, pod warunkiem wyeksportowania go w każdej komendzie. Jedno przeoczenie ponownie łączy OpenCode z Twoim prawdziwym katalogiem domowym, wliczając skille innych narzędzi: dwa skille-wabiki to potwierdzają, a lista bezHOMEwyciąga ich 120. - Skill projektu i lokalne narzędzie MCP działają razem już od pierwszej próby, bez identyfikatora, z darmowym modelem
big-pickleOpenCode Zen. - Uprawnienia
asksą automatycznie odrzucane w trybie nieinteraktywnym, ale kod wyjścia pozostaje 0: do obserwowania, jeśli skryptujesz weryfikacje wokółopencode run. - Modele lokalne (Ollama, llama.cpp, LM Studio) przechodzą przez generycznego dostawcę kompatybilnego z OpenAI, do zadeklarowania ręcznie, nie przez dedykowaną integrację Ollama.
Częste błędy
~/.claude/skills i ~/.agents/skills są czytane automatycznie To nie defekt izolacji: potwierdza to wbudowana dokumentacja (external skills, auto-loaded). Na maszynie już wyposażonej dla Claude Code, jego skille tam trafiają bez jawnej deklaracji.skill Lista skilli nie pojawia się w opencode --help: jest ukryta pod opencode debug skill, narzędziem diagnostycznym, które może się zmienić bez ostrzeżenia.~/.config/opencode, nie ~/.opencode Wbudowana dokumentacja wyraźnie precyzuje tę pułapkę nazewnictwa, druga ścieżka jest po cichu ignorowana.opencode run i tak kończy się kodem 0.

