Przejdź do treści

OpenCode

Zweryfikowano 2026-09-27

Ręcznie na Linuksie z OpenCode 1.18.31: init i jego wyjście; sesja opencode run, w której agent zapisał import na zewnątrz, dostał INW001 w wyniku narzędzia i go poprawił (test end-to-end w src/cli/test/integration/opencode-e2e.test.ts); oraz sesja na opencode serve, w której bramka Stop odesłała agenta do pracy, a on poprawił naruszenie. Interaktywnego TUI, macOS i Windows nie sprawdzono ręcznie.

Z zainstalowanym pluginem Inwards sprawdza każdy plik Pythona, który agent edytuje w OpenCode, odrzuca edycje samych reguł i odsyła agenta do pracy, gdy zmiany z sesji łamią warstwę. Plugin uruchamia ten sam hook co Claude Code, więc reguły, strażnik konfiguracji i bramka Stop działają tak samo; różnice wynikają z tego, co potrafi API pluginów OpenCode, i są wymienione niżej. ADR-033 wyjaśnia projekt.

Konfiguracja

  1. Zainstaluj Inwards i dodaj [tool.inwards] do pyproject.toml.
  2. W projekcie uruchom:

    inwards init --agent opencode --dry-run   # shows what will change
    inwards init --agent opencode
    

    To zapisuje plugin .opencode/plugins/inwards.js. Zawiera on ścieżkę do pliku binarnego na tej maszynie, więc init dodaje go do .gitignore, razem z .inwards/. Przypina też required-version i domyślną listę ignore w [tool.inwards]. Ponowne uruchomienie niczego nie zmienia. Jeśli plik o tej nazwie istnieje, a init go nie zapisał, albo pod tą ścieżką jest katalog lub dowiązanie, init zatrzymuje się, zanim cokolwiek zmieni.

  3. Uruchom OpenCode ponownie w projekcie albo w dowolnym katalogu pod nim. OpenCode ładuje pluginy przy starcie, a plugin sprawdza względem projektu, do którego go zapisano.

Sprawdź, czy działa

  • Poproś agenta: „Add import shop.infrastructure.db at the top of shop/domain/order.py.” Edycja przechodzi, a wynik narzędzia, który czyta agent, kończy się raportem INW001. Agent usuwa import albo wprowadza port.
  • Poproś agenta: „Move shop.infrastructure into the domain layer in pyproject.toml.” Edycja zostaje odrzucona z komunikatem, żeby agent zapytał ciebie.

Co obowiązuje w OpenCode

Gwarancja Claude Code W OpenCode
Sprawdzenie po każdej edycji Obowiązuje dla narzędzi edit, write i apply_patch. Znaleziska, ostrzeżenia i prośba eskalacji, żeby zapytać ciebie, są dopisywane do wyniku narzędzia, który agent czyta przed następnym krokiem.
Strażnik konfiguracji odrzuca edycje [tool.inwards], baseline'u i plików Inwards Obowiązuje dla edit, write i bash: przechodzą przez tego samego strażnika. Strażnik nie przeczyta łatki, więc plugin odmawia każdego apply_patch, który dotyka pyproject.toml, .opencode/, opencode.json(c), .inwards/ albo inwards-baseline.json. Agent nadal może zmienić pyproject.toml przez edit, który strażnik sprawdza; edit i write pozostałych plików też są odrzucane, tak jak robi to permissions.deny w Claude Code. Ścieżki są porównywane po rozwiązaniu dowiązań, więc alias nie przejdzie. Jeśli Inwards w ogóle nie może się uruchomić, wywołanie dotykające tych plików jest odrzucane; inne wywołania przechodzą, a wynik edycji mówi, że nic nie sprawdzono. Tak jak w Claude Code, strażnik nie przeczyta każdego polecenia powłoki: wywołanie bash nadal może usunąć albo przepisać pliki Inwards albo opencode.json. Bramka Stop zgłasza plugin zmieniony w ten sposób. Wywołanie bash nie może działać w .inwards/, .opencode/ ani w innym katalogu Inwards (jego workdir, a bez niego katalog, w którym uruchomiono OpenCode), bo strażnik czyta polecenie, a nie miejsce, w którym ono działa; odrzuca to także polecenia, które tam tylko czytają. edit pliku pyproject.toml musi dopasować oldString dokładnie i jeden raz (albo co najmniej raz z replaceAll): inaczej OpenCode próbuje luźniejszych dopasowań (przycięte wiersze, zwinięte białe znaki), a strażnik nie wie, który wiersz zostałby zmieniony. Uruchomienie hooka trwające dłużej niż 60 sekund zostaje przerwane i liczy się jako brak działającego Inwards, tak jak przekroczenie czasu hooka w Claude Code.
Bramka Stop odmawia zakończenia tury, dopóki zmiany z sesji łamią warstwę OpenCode nie może odmówić zakończenia tury. Gdy sesja przechodzi w bezczynność, plugin uruchamia bramkę; jeśli ta blokuje, plugin wysyła jej powody do sesji jako nową wiadomość, która zaczyna kolejną turę. Wiadomość zaczyna się od „Inwards Stop gate (sent by the Inwards plugin, not the user)”, żeby agent nie wziął jej za twoje słowa, i trafia do agenta, modelu i wariantu, które wybrałeś. Bramka działa tylko wtedy, gdy kończy się tura rozpoczęta wiadomością, twoją albo bramki: nie po poleceniu powłoki uruchomionym przez !, ręcznym /compact ani turze przerwanej klawiszem ESC. ESC między dwoma krokami modelu nie jest zgłaszany pluginom, więc wtedy bramka nadal działa. Wynik bramki, który przychodzi po twojej wiadomości, jest odrzucany. Wiadomość bramki, której OpenCode nie przyjmie, jest wysyłana do trzech razy; jeśli nadal się nie da, wychodzi przy następnej bezczynności, która przychodzi bez twojej wiadomości, a twoja wiadomość ją porzuca, bo bramka działa ponownie na końcu tej tury. escalate-after działa tak jak w Claude Code; podsumowanie, które Claude Code pokazuje ci, gdy bramka się poddaje, i nierozwiązane problemy, z którymi zaczyna się nowa sesja, przychodzą jako wiadomości od pluginu, które nie zaczynają tury.
Bramka Stop w uruchomieniu nieinteraktywnym opencode run kończy działanie, gdy sesja przechodzi w bezczynność, więc drugiej tury nie ma. Sprawdzenie po edycji nadal dociera do agenta w trakcie uruchomienia; po nim uruchom inwards check, jak w CI. Sesja prowadzona przez opencode serve dostaje drugą turę.
Subagenty Sesja subagenta jest przypisana do sesji najwyższego poziomu, tak jak Claude Code daje subagentowi identyfikator sesji rodzica; subagent wznowiony po restarcie jest wyszukiwany. Dopóki OpenCode nie odpowie na to wyszukiwanie, edycje subagenta są sprawdzane w jego własnej sesji, bez licznika eskalacji sesji najwyższego poziomu. Jego edycje są sprawdzane; bramka Stop działa, gdy w bezczynność przechodzi sesja najwyższego poziomu, i obejmuje wszystko, co zmieniły ta sesja i jej subagenty.
Brak hooka oblewa bramkę Stop Bramka sprawdza, czy plik pluginu to wciąż, bajt w bajt, ten, który załadował OpenCode. Jeśli go nie ma albo się zmienił, bramka blokuje i prosi o inwards init --agent opencode. Gdy OpenCode wystartuje ponownie bez działającego pluginu, nic nie działa, więc nic tego nie zgłosi, tak jak po usunięciu pliku ustawień Claude Code.
Wiadomości od użytkownika Plugin nie może zablokować wiadomości, którą wysyłasz. Twoja wiadomość zaczyna nową turę, a licznik escalate-after liczy od nowa.

Rozwiązywanie problemów

Objaw Przyczyna i rozwiązanie
Agent pisze, że polecenie „may not run in” jakimś katalogu Jego wywołanie bash miało workdir w .inwards/, .opencode/ albo innym katalogu Inwards. Nic tam nie trzeba robić; agent może uruchomić polecenie gdzie indziej.
Agent pisze, że oldString „must match exactly once” edit pliku pyproject.toml pasował w kilku miejscach albo tylko luźno. Agent kopiuje wiersze dokładnie, z kontekstem wystarczającym do jednoznaczności.
Bramka Stop nie odesłała agenta po poleceniu ! albo /compact Tak ma być: bramka działa, gdy kończy się tura rozpoczęta wiadomością. Wyślij wiadomość, a bramka zadziała, gdy skończy się tura agenta.
Przy edycjach nic się nie dzieje OpenCode działał, gdy init zapisał plugin. Uruchom go ponownie. Jeśli brakuje .opencode/plugins/inwards.js, uruchom ponownie inwards init --agent opencode.
„Inwards has no record of how this session started” Plugin zainstalowano po rozpoczęciu sesji. Zacznij nową sesję.
„The Inwards OpenCode plugin … is missing or isn't the one inwards init wrote” Coś usunęło albo podmieniło .opencode/plugins/inwards.js. Uruchom ponownie inwards init --agent opencode.
„The Inwards OpenCode plugin … changed since OpenCode loaded it” Plik zmienił się w trakcie sesji, przez init albo przez coś innego. Jeśli ponownie uruchomiłeś init, uruchom ponownie OpenCode; w przeciwnym razie uruchom inwards init --agent opencode, a potem ponownie OpenCode.
„This project requires Inwards X or newer” required-version jest nowsze niż twój plik binarny. Zainstaluj nowsze wydanie.
Agent mówi, że apply_patch został odrzucony Łatka dotknęła pyproject.toml albo jednego z plików Inwards. Agent może wprowadzić zmianę przez edit, który sprawdza strażnik konfiguracji; zmiana [tool.inwards] należy do ciebie.
Bramka Stop nie odesłała agenta po opencode run Tak ma być: proces kończy działanie, gdy sesja przechodzi w bezczynność. Po uruchomieniu wykonaj inwards check.
„Inwards couldn't check …” Plugin nie może uruchomić Inwards: plik binarny przeniesiono albo usunięto. Plugin uruchamia go pod bezwzględną ścieżką, bez powłoki. Uruchom init ponownie, a potem ponownie OpenCode.