uriloop
AI Cost Tracking
- 🤖 LLM usage: $0.5831 (12 commits)
- 👤 Human dev: ~$691 (6.9h @ $100/h, 30min dedup)
Generated on 2026-10-30 using openrouter/qwen/qwen3-coder-next
Wspólna płaszczyzna URI/URN do autonomicznego sterowania przeglądarką (CDP) i pulpitem (noVNC/VNC)
przez MCP, z warstwową analizą ekranu, pętlą zwrotną nad TODO.md i wzorcem CQRS + Event Sourcing
(logs.jsonl → chat.jsonl, PostgreSQL).
Zgodność z wytycznymi wellmanifest: nl-uri-dsl-llm (NUL-001…009, 015), logs (hash-chain JSONL, runbooki),
poa (typowane procesy, kwity, fail-closed), ssot (ssot.json), reuse (rejestr deklaratywny, fasady), dsl (dsl-manifest.json).
AI: decyzje, generowanie procesów, wizja
| Rola | Model (domyślnie) | Co robi |
|---|---|---|
| Decyzje | Liquid d1 d1:3b przez Ollama /v1/systemone |
wybiera Action URI z katalogu (2..255 kandydatów, także elementy ekranu po URN), ocenia ryzyko 1..3 i zgodę na wykonanie; widzi zrzut ekranu |
| Generator | qwen3:8b (GPU 8 GB) · qwen3.8:27b-q4_K_M (≥ 20 GB) · DeepSeek deepseek-v4-flash/pro · proxy subllm |
tworzy proces złożony proc://uriloop/<nazwa> z kroków rejestru, z pętlą poprawek po walidacji |
| Wizja | YOLO (ultralytics lub onnxruntime) |
detekcje z URN i akcjami kliknięcia na pulpicie i stronie |
make ollama-pull # natywnie: modele dobrane do VRAM (np. d1:3b + qwen3:8b)
make models # telemetria GPU i wybrane profile
make decide Q='kliknij Powitanie' X=1 # decyzja d1 (+ wykonanie, jeśli polityka pozwala)
make generate G='wyszukaj uriloop, a następnie otwórz drugą stronę' R=1
make generate G='…' P=deepseek # z DEEPSEEK_API_KEY
make detect SRC=desktop # YOLO
W pętli: zadanie bez kroków → NL → decyzja d1 → (gdy wieloetapowe lub niepewne) generator → proc:// → weryfikacja.
Zablokowane przez politykę (URILOOP_AUTONOMY, negacja „nie klikaj…”) dostaje [?] i czeka na człowieka.
Szczegóły: docs/AI.md.
Szybki start
Granica wdrożenia: Ollama (d1, qwen), YOLO i ciężkie pakiety (onnxruntime, ultralytics/torch) działają natywnie na hoście — z bezpośrednim dostępem do GPU i bez wielogigabajtowych obrazów. Docker uruchamia tylko lekką infrastrukturę: Postgres, Chrome (CDP), pulpit (VNC/noVNC), stronę demo i projektor CQRS.
make host-setup # .venv + uriloop[pg,vnc,onnx] + sprawdzenie Ollamy + `ollama pull` modeli dobranych do VRAM
# INSTALL_OLLAMA=1 make host-setup — instalacja Ollamy oficjalnym skryptem
# WITH_YOLO=1 make host-setup — ultralytics (torch zainstaluj wcześniej z właściwym CUDA)
source .venv/bin/activate # udostępnia uriloop w bieżącej powłoce, także po pracy w conda (base)
export URILOOP_ROOT="$PWD/workspace"
make up # docker: postgres, chrome (CDP 127.0.0.1:9222), desktop (VNC :5901, noVNC :6901), demo (:8088), projektor
make doctor # host: Ollama, modele, GPU, pakiety · docker: CDP, VNC, Postgres
make run-dry # plan: TODO.md → Action URI (bez wykonania)
make run # pętla autonomiczna na hoście; obserwuj workspace/TODO.md i workspace/chat.jsonl
make tail # zdarzenia
make verify # łańcuch hashy
make db-shell # select * from chat_view; select * from elements_view;
Ollama działa jak zwykle na hoście (ollama serve lub usługa systemowa) pod http://127.0.0.1:11434.
Usługi docker są wystawione tylko na 127.0.0.1. Opcjonalny kontener agent (make agent-docker A='todo')
nie zawiera AI; jeśli ma korzystać z Ollamy hosta, ustaw URILOOP_AI_IN_DOCKER=on i uruchom Ollamę z OLLAMA_HOST=0.0.0.0.
Katalog workspace/ jest współdzielony: projektor w kontenerze działa z UID/GID użytkownika (eksportuje je make),
więc pliki projekcji pozostają zapisywalne dla procesów hosta. Na macOS (Docker Desktop) blokady plików między
hostem a kontenerem bywają zawodne — tam uruchom projektor natywnie (make follow) zamiast usługi projector.
Podgląd pulpitu: http://localhost:6901/vnc.html?password=vncpassword.
Interaktywny shell i przykłady
make shell uruchamia terminal ze stałym Runtime oraz bramą narzędzi MCP. Analiza i kliknięcie po URN zachowują wspólną sesję. make mcp nadal udostępnia serwer stdio dla zewnętrznego klienta MCP.
uriloop> help
uriloop> tools
uriloop> scenarios
uriloop> scenario-plan demo-complex
uriloop> scenario demo-complex http://127.0.0.1:18089/
uriloop> do browser://page/analyze
uriloop> call chat_message_post {"text":"Sprawdzenie zakończone"}
uriloop> quit
Dostępne przykłady: demo-search, demo-data, demo-complex, demo-form, demo-table, demo-files, demo-tabs, demo-auth. Wykonują analizę przed kliknięciem, wybierają bieżący URN, sprawdzają wyniki pośrednie i zapisują raport jako artefakt. Błąd zatrzymuje scenariusz; nie ma automatycznych ponowień efektów. URL wskazuje serwer demo widoczny dla sterowanej przeglądarki. Można też użyć make scenarios oraz make scenario NAME=demo-complex URL=http://127.0.0.1:18089/.
Terminal przyjmuje Action URI, nl TEKST, plan CEL i call NAZWA JSON. plan zapisuje plan do osobnego późniejszego wykonania przez proc://uriloop/run?name=.... help, tools i quit sterują terminalem; działania systemu przechodzą przez rejestr i MCP. Shell obsługuje lokalny katalog uriloop; nie jest klientem dowolnego zewnętrznego serwera MCP.
Seria scenariuszy i CI
make suite wykonuje wszystkie osiem gotowych scenariuszy, każdy w oddzielnej sesji i katalogu. Całość wymaga grantów i fikcyjnych danych do logowania:
URILOOP_GRANTS=browser.upload,browser.tabs.close,browser.secrets \
URILOOP_SECRET_DEMO_PASSWORD=uriloop-demo-only \
URILOOP_SECRET_DEMO_BAD_PASSWORD=wrong-demo-password \
make suite URL=http://127.0.0.1:18089/
W shellu uruchomionym z tymi ustawieniami odpowiednikiem jest suite http://127.0.0.1:18089/. Akcja scenario://suite/run zapisuje raport JSON, JUnit XML, kwity i logi; błąd dowolnego scenariusza daje exit 1. Można wybrać podzbiór parametrem names i limit czasu jednego przypadku parametrem timeout.
make suite-local OUT=/tmp/nowe-wyniki CHROME_BIN=/sciezka/do/chrome uruchamia własne Chromium i serwer demo na wolnych portach. Wymaga pustego katalogu wyników. Workflow GitHub Actions sprawdza Python 3.11 i 3.13 i zachowuje raporty nawet po niepowodzeniu. Szczegóły: docs/CI.md.
Rzeczywisty VNC i PostgreSQL są sprawdzane osobnym jobem real-infrastructure: tekst jest wpisywany do aplikacji xterm i weryfikowany w pliku, a lustro bazy porównywane z logiem także po awarii połączenia i replay. Lokalne uruchomienie opisuje docs/CI.md. Synchronizacja bazy ma teraz Action URI log://mirror/sync.
Nowe strony demo: formularz kontaktu (forms.html) i lista zamówień (table.html). Scenariusze otwierają je względem bazowego URL demo. Dane pozostają w pamięci strony do jej przeładowania.
uriloop> scenario demo-form http://demo/
uriloop> scenario demo-table http://demo/
demo-form sprawdza pola wymagane, niepoprawny e-mail, zastąpienie tekstu i checkbox. demo-table sprawdza filtr, sortowanie, anulowanie i potwierdzenie modala oraz odmowę kliknięcia zasłoniętej kontrolki. Polecenie browser://page/type przyjmuje clear=true, aby zastąpić zawartość wskazanego pola; wymaga wtedy URN lub selektora.
Scenariusz plikowy wymaga grantu operatora:
URILOOP_GRANTS=browser.upload ./uriloop shell
# W terminalu uriloop:
# scenario demo-files http://demo/
demo-files pobiera raport UTF-8, sprawdza nazwę, MIME, bajty i SHA-256, wykrywa HTTP 404, załącza niewłaściwy typ, czyści wybór i zapisuje poprawny załącznik dokładnie raz w atrapie. Plik jest odczytywany w formularzu lokalnie; atrapa nie wysyła go do serwera. Runner make suite-local sam przyznaje potrzebne granty i ustawia jawne dane fikcyjnego konta dla własnego Chromium i lokalnych stron demo.
browser://file/fetch?urn=… pobiera zawartość linku przez Fetch w przeglądarce do artefaktu w katalogu roboczym. Obsługuje HTTP(S) tej samej domeny, bez przekierowań, maksymalnie 5 MiB i z ograniczonym czasem. Kwit zwraca metadane pliku i artefakt; błąd, timeout lub niekompletny transfer nie tworzy artefaktu plikowego. To ścieżka pobierania przez Fetch; natywny menedżer pobierania i dialog zapisu wymagają osobnych testów.
browser://page/attach?urn=…&artifact=artifacts/…&name=raport.txt&mime=text/plain wybiera jeden artefakt we wskazanym polu plikowym. clear=true czyści wybór. Wymaga grantu browser.upload, aktualnego celu i zgodnego hasha pliku; nie odczytuje dowolnych ścieżek hosta. Transfer bajtów przez CDP działa także wtedy, gdy Chromium jest w innym kontenerze. Używa File/DataTransfer; formularze wymagające zaufanych zdarzeń systemowych lub natywnego dialogu nie są jeszcze obsługiwane.
Scenariusz kart otwiera dwie kopie tej samej strony i sprawdza oddzielny stan notatek, odrzucenie URN z innej karty oraz zachowanie po zamknięciu wybranej karty:
URILOOP_GRANTS=browser.tabs.close ./uriloop shell
# W terminalu uriloop:
# scenario demo-tabs http://demo/
browser://tabs/list zwraca URN, URL, tytuł i informację o karcie wybranej w Runtime. browser://tabs/open przyjmuje albo url, albo URN linku z analizy; otwiera i wybiera nową kartę. browser://tabs/switch?urn=… wybiera wskazaną kartę. browser://tabs/close?urn=… wymaga grantu browser.tabs.close. Po zamknięciu wybranej karty trzeba jawnie wskazać kolejną przez switch; zwykła akcja strony nie wybiera automatycznie sąsiedniej karty. Zamknięcie karty w tle zachowuje wybraną kartę i jej indeks.
URN elementów i formularzy uwzględnia kartę, także przy identycznym URL. Przełączenie czyści indeks, poprzedni obraz i obserwację; nowa sesja CDP ma osobną historię żądań. open otwiera adres linku bez wykonywania jego handlera JavaScript. Okna popup, iframe, pobieranie danych między formularzami i odzyskiwanie niezapisanej pracy wymagają dalszych scenariuszy.
Logowanie demonstracyjne:
URILOOP_GRANTS=browser.secrets \
URILOOP_SECRET_DEMO_PASSWORD=uriloop-demo-only \
URILOOP_SECRET_DEMO_BAD_PASSWORD=wrong-demo-password \
./uriloop shell
# W terminalu uriloop:
# scenario demo-auth http://demo/
To jawne dane fikcyjnego konta. demo-auth sprawdza niepoprawne dane, zalogowanie, odświeżenie, odmowę dostępu, wygaśnięcie i wylogowanie. Kody 200/401/403 są komunikatami lokalnej symulacji w sessionStorage; nie są odpowiedziami serwera uwierzytelniania. Backend, ciasteczka, SSO i MFA wymagają kolejnych testów.
browser://page/secret?urn=…&env=URILOOP_SECRET_PASSWORD odczytuje wartość z otoczenia procesu operatora i wpisuje ją wyłącznie do wskazanego pola hasła. Wymaga grantu browser.secrets, świeżego URN, poprawnego fokusu i nazwy zmiennej zaczynającej się od URILOOP_SECRET_. Nie zatwierdza formularza. W URI, kwicie i błędzie sterownika pozostaje referencja, bez wartości ani jej długości. Zwykłe browser://page/type odrzuca pole hasła; tekst tej komendy jest maskowany w publicznym URI także przy błędzie kontraktu. URI z maską jest dowodem audytu, a nie sposobem odtworzenia wpisanej treści.
Sekrety przekazuj przez referencję środowiskową, również w procesach złożonych. Nie umieszczaj ich w NL, TODO, kodzie procesu, eval ani innych parametrach URI. Ochrona dotyczy tej ścieżki wprowadzania i standardowych pól hasła; nie zapewnia maskowania dowolnych danych widocznych na ekranie ani treści, którą strona sama ujawni poza polem hasła.
Dostęp do polecenia uriloop
Instalacja znajduje się w .venv. Skrypt make host-setup aktywuje ją tylko wewnątrz swojego procesu. W nowym terminalu aktywuj środowisko przez source .venv/bin/activate, aby używać polecenia uriloop. W katalogu projektu można od razu używać ./uriloop albo .venv/bin/uriloop bez aktywacji. Launcher ./uriloop wybiera Python projektu i domyślnie zapisuje zdarzenia do workspace/; respektuje jawne URILOOP_ROOT i --root.
./uriloop --help
./uriloop nl 'wpisz „uriloop” ' --dry
./uriloop shell
# Alternatywnie, w bieżącym terminalu:
source .venv/bin/activate
export URILOOP_ROOT="$PWD/workspace"
uriloop --help
nl 'wpisz …' wpisuje do pola, które ma fokus. Do przykładu z wyszukiwaniem i weryfikacją wyniku użyj w shellu scenario demo-search http://demo/. Samo uruchomienie CLI nie wymaga goal -a.
Goal: dostarczenie zmian do prywatnego repozytorium
Do commitu i push bez wydania pakietu użyj:
make deliver
# To samo bez Make:
goal -a --no-publish push --no-version-sync --no-tag --no-changelog
# Podgląd bez wykonywania zmian:
goal -a --no-publish --dry-run push --no-version-sync --no-tag --no-changelog
W Goal 2.2.4 samo -a włącza również --force-publish. Przy czystym drzewie i braku bazowej wersji z tagów, rejestru lub historii Goal proponuje normal-bump, po czym odmawia publikacji: clean --force-publish requires an already synchronized, pre-bumped release version. To konflikt w przebiegu wydania Goal; ponowienie tego samego polecenia nie przygotuje wydania. Linie VERSION ... -> ... w tym komunikacie opisują plan, a nie wykonany zapis.
Samo --no-publish pomija publikację pakietu; pozostałe flagi w make deliver wyłączają także synchronizację wersji, tagowanie i generowanie changeloga. Podgląd Goal 2.2.4 może nadal wyświetlić hipotetyczne podbicie wersji mimo tych flag; wykonanie korzysta ze ścieżki commitu bez wydania. Goal nadal może przygotować środowisko oraz zmienić pliki konfiguracyjne, utworzyć commit i wykonać push bieżącej gałęzi. Do uruchomienia aplikacji wystarczy ./uriloop shell, a do lokalnej kontroli make test i make verify.
Ostrzeżenie AI badge generation failed pochodzi z dodatkowego mechanizmu szacowania kosztów i jest oddzielne od błędu wydania. Nie wymaga dodawania klucza OpenRouter do uruchamiania CLI ani deterministycznych scenariuszy. Wydanie do rejestru pakietów jest osobnym procesem: wymaga świadomego wyboru wersji, jej synchronizacji i konfiguracji docelowego rejestru.
Pojedyncze polecenia
uriloop do 'browser://page/navigate?url=http://demo/'
uriloop do 'browser://page/analyze?format=webp' # zwraca URN elementów + gotowe akcje
uriloop do 'browser://page/click?urn=urn:uriloop:el:3f9c0a1b2c4d'
uriloop nl 'wpisz „uriloop” ' # NL → browser://page/type?text=uriloop
uriloop do 'desktop://keyboard/key?key=ctrl+l'
uriloop do 'desktop://screen/analyze?grid=12'
uriloop snapshot # NUL-009: stan rozmowy, procesów, zadań
MCP
Narzędzia są generowane z registry/processes.json (nazwa = URI: browser://page/click → browser_page_click),
plus uri_execute (dowolne URI) i nl_execute (polecenie w języku naturalnym). Zrzuty wracają jako treść image.
Zasoby: TODO.md, chat.jsonl, state.json, logs.jsonl, uriloop://registry/gbnf.
make mcp-browser # profil CDP (natywnie, stdio)
make mcp-desktop # profil noVNC (natywnie, stdio)
Konfiguracja klienta: .mcp.json uruchamia serwery z .venv na hoście (ustaw URILOOP_HOME na katalog projektu).
TODO.md — kolejka zadań
- [ ] Wyszukaj frazę formularzem
- `browser://page/type?selector=%23q&text=uriloop&submit=true`
- expect: url~search.html?q=uriloop
- expect: text~Fraza: uriloop
- [ ] przejdź do http://demo/page2.html ← bez kroków: NL → URI
- expect: text~Nawigacja zakończona sukcesem
Statusy [~] w toku, [x] wykonane, [!] nieudane ustawia projektor ze zdarzeń; dopisuje też <!-- urn:uriloop:task:… -->.
Pliki robocze (workspace/)
| Plik | Rola |
|---|---|
logs.jsonl |
Event store: append-only, prev/hash SHA-256, jedyne źródło prawdy |
chat.jsonl |
Projekcja rozmowy: wiadomości + zwięzłe powiadomienia procesów z URI/URN |
state.json |
Projekcja zasobów po URN (elementy, żądania, artefakty, procesy, zadania) |
TODO.md |
Zadania (pisze człowiek) + statusy (pisze projektor) |
artifacts/ |
PNG/WebP, Set-of-Mark, JSON warstw — adresowane treścią |
Struktura
registry/processes.json SSOT akcji (URI, schematy, aliasy NL, efekty)
src/uriloop/uri.py Action URI / URN, stable_urn
src/uriloop/runtime.py szyna komend + handlery (CQRS write)
src/uriloop/eventstore.py logs.jsonl + lustro PostgreSQL + artefakty
src/uriloop/projector.py projekcje (CQRS read), follow/rebuild
src/uriloop/loop.py pętla autonomiczna z expect i ponowieniami
src/uriloop/analysis/ warstwy L0–L4, sonda DOM, Set-of-Mark
src/uriloop/drivers/ cdp.py, vnc.py (RFB 3.8, TCP lub WebSocket noVNC)
src/uriloop/mcp/server.py serwer MCP stdio
src/uriloop/ai/ router (NUL-022), decision (d1/System One), generator (qwen/DeepSeek), vision (YOLO)
src/uriloop/composites.py procesy złożone proc://uriloop/<nazwa>, katalog DockURI
registry/models.json SSOT modeli i profili
db/init.sql tabela events (append-only) + widoki read-modeli
Szczegóły: docs/ARCHITECTURE.md, zasady dla agentów: AGENTS.md, runbooki: errors/.
Testy
make test — 110 testów, w tym kontrola granicy wdrożenia (brak Ollamy/GPU/torch w compose i obrazie, MCP natywnie, doctor), warstwa AI na atrapie Ollama/DeepSeek (router GPU 8 GB, kontrakt d1, polityki, pętla poprawek generatora, YOLO ONNX) i E2E zadania złożonego (d1 → generator → proc:// → weryfikacja na żywym Chromium). Pozostałe: URI/rejestr/NL, event store i projekcje, schematy, klient RFB vs atrapa serwera (TCP i WebSocket),
warstwy analizy, kontrakt MCP oraz E2E z prawdziwym Chromium (pętla nad TODO.md, MCP po stdio), uruchamiane gdy przeglądarka jest dostępna.
Ograniczenia i dalsze kroki
- Analiza pulpitu jest pikselowa (siatka, zmiany); rozpoznawanie tekstu/ikon (OCR, VLM na Set-of-Mark) to następny krok.
- Klient VNC obsługuje kodowania Raw/CopyRect; dla wolnych łączy warto dodać Tight/ZRLE.
- Klienci d1, qwen i DeepSeek są przetestowani na atrapach zgodnych z opublikowanymi kontraktami API, nie na prawdziwych modelach.
- Format katalogu DockURI jest własnym profilem — repozytorium dockuri/dockuri było niedostępne.
License
Licensed under Apache-2.0.
Metadata
Release files for uriloop 0.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| uriloop-0.3.2.tar.gz | 117.4 kB | Without provenance | Details for uriloop-0.3.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| uriloop-0.3.2-py3-none-any.whl | Python 3 | none | any | Details for uriloop-0.3.2-py3-none-any.whl |
Total release size: 213.2 kB
Release files / uriloop-0.3.2.tar.gz
| Download URL | uriloop-0.3.2.tar.gz |
|---|---|
| Size | 117.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
498d741284f1e79d2b46f435cec95ef792164fac3bf08d3b97adf39e440ef7e1
|
|
BLAKE2b-256 checksum How to use checksums |
e3a6c6c50a28e008d11c4f8ed55a1994d8aaaabe56cedb9f1e9a13e19c930acd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.7
|
Release files / uriloop-0.3.2-py3-none-any.whl
| Download URL | uriloop-0.3.2-py3-none-any.whl |
|---|---|
| Size | 95.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
563a7b86803e8cb1f280513703314a29652fa49b0fa8de2b63563ad74f66f1b9
|
|
BLAKE2b-256 checksum How to use checksums |
63568387ce0611b32ca7899bc0b15b5be5426bcbc046eabe179ef538ce44ba04
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.7
|
Security for uriloop 0.3.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.