Dokumen desain teknis untuk fitur dasbor sesi, yang ditulis sebelum dan
selama implementasi. Dokumen ini menjadi sumber acuan utama untuk pengembangannya. Saat
fitur dirilis,
/web/dashboard menjadi halaman yang ditujukan bagi pengguna dan halaman ini tetap
menjadi referensi arsitektur.Visi
Saat ini, bekerja dengan agen berupa aliran teks. Dasbor mengubahnya menjadi meja kerja: agen merender widget langsung yang interaktif; pengguna menyematkannya ke permukaan persisten; obrolan ditambatkan ke samping (atau disembunyikan) dan konten utama adalah papan. Anda beralih dari “berbicara dengan agen” menjadi “mengoperasikan panel kontrol yang dibuat agen untuk Anda” tanpa pernah meninggalkan sesi. Prinsip:- Papan adalah salah satu tampilan sesi, bukan objek baru. Setiap sesi (utas)
memiliki dua tampilan: transkrip dan papan. Sesi tanpa widget yang disematkan
adalah obrolan biasa. Sematkan satu widget dan papan pun tersedia. Papan mewarisi
identitas sesi, kepemilikan agen, penamaan, penyematan, dan siklus hidup. Tidak ada
dashboard_create, registri papan, ataupun model ACL terpisah. - Kesetaraan agen. Segala hal yang dapat dilakukan pengguna pada papan, dapat dilakukan agen dengan alat: menambahkan/memperbarui/menghapus widget, mengaturnya, mengelola tab, mengganti tab yang terlihat, serta menambatkan atau menyembunyikan obrolan.
- Native, bukan tersemat. Papan terdiri dari komponen Lit dalam shell Control UI (sistem desain yang sama dengan bagian aplikasi lainnya). Hanya konten widget yang diisolasi dalam iframe. Tidak ada bilah URL atau krom peramban.
- Permukaan agen yang kecil. Widget dituju berdasarkan nama stabil dan diperbarui di tempat. Tata letaknya berupa kisi fleksibel yang memadat otomatis; agen menyatakan ukuran dan jangkar, bukan piksel atau koordinat.
- Kapabilitas, bukan kepercayaan. Kode widget adalah HTML/JS arbitrer buatan agen dalam sandbox yang ketat. Jangkauan (data Gateway, tindakan, jaringan) hanya tersedia melalui manifes kapabilitas yang dideklarasikan dan diberikan oleh operator.
Konsep
Alur UX
- Promosi: agen memanggil
show_widgetdalam obrolan apa pun → widget dirender sebaris dalam transkrip persis seperti saat ini → mengarahkan kursor menampilkan Sematkan ke dasbor → widget muncul pada papan sesi. Agen dapat meneruskanpin: trueuntuk melakukan hal yang sama. - Tampilan papan: sesi yang memiliki papan mendapatkan pengalih tampilan (Obrolan / Dasbor). Tampilan papan = strip tab (hanya jika >1 tab) + kisi fleksibel + panel obrolan tertambat. Tambatan obrolan dapat diubah ukurannya, dipindahkan (kiri/kanan/bawah), dan diciutkan persis seperti bilah sisi. Status tambatan per tab diingat.
- Seret: pengguna menyeret widget; kisi memadat otomatis (widget mengambang ke atas, widget di sekitarnya mengalir ulang). Pengubahan ukuran melalui pegangan menyesuaikan ke tahapan ukuran. Tidak ada penempatan berdasarkan piksel — bagi siapa pun.
- Peringatan reset:
/new//resetpada sesi yang memiliki papan meminta konfirmasi di UI web (“konteks direset, dasbor tetap ada”) dan mempertahankan papan. - Bilah sisi: sesi tersemat merender tampilan papannya jika tersedia. Papan sesi Beranda adalah “dasbor agen” default.
- Interaksi (tiga tingkat, lihat di bawah): peristiwa status senyap, pengiriman prompt yang terlihat, dan pemicu otomatisasi.
Tingkat interaksi
- Peristiwa status (default). Interaksi UI widget yang perlu diketahui model
tetapi tidak perlu ditanggapi.
bridge.emitState({...})menambahkan pemberitahuan sesi terstruktur (mekanisme yang sama dengan pemberitahuan aktivitas grup). Tidak ada giliran agen yang dimulai; model melihat pemberitahuan yang terakumulasi pada proses berikutnya. - Prompt (percakapan eksplisit).
bridge.sendPrompt(text)— memerlukan aktivasi pengguna; mengirim pesan pengguna yang terlihat ke dalam sesi (obrolan tertambat menampilkannya). Dibatasi lajunya; setiap pengiriman dikonfirmasi pengguna kecuali widget memiliki pemberian kapabilitasprompt. - Otomatisasi.
bridge.runAction(name, args)— memicu tindakan yang dideklarasikan dalam manifes. Kumpulan verba awal:cron.trigger(jalankan tugas Cron yang sudah ada sekarang) danbinding.refresh. Tugas Cron sudah berjalan dalam sesi proses terisolasi yang terlihat dan dapat menggunakan model yang lebih murah: itulah jalur “model kecil mendukung widget”. Tidak ada sesi tersembunyi di mana pun.
Model dan hosting widget
HTML/JS widget dibuat oleh agen (biasanya melaluishow_widget), dibungkus
dalam shell dokumen standar (meta CSP, pelapor ukuran, bootstrap jembatan), dan
dirender dalam <iframe sandbox="allow-scripts"> (tidak pernah allow-same-origin).
- Widget sebaris (transkrip) mempertahankan pipeline dokumen canvas saat ini: ditulis di bawah direktori status, dilayani oleh Gateway, dipangkas per cakupan, tanpa persetujuan (widget tersebut secara konstruksi tidak memiliki kapabilitas — pengiriman prompt dikonfirmasi pengguna).
- Widget papan adalah status sesi: bita berada di DB SQLite milik agen
(
board_widgets), dilayani oleh rute Gateway inti (/__openclaw__/board/<agentId>/<sessionKey>/<name>/) yang membaca DB. Menyematkan widget transkrip akan menyalin bitanya. Batas: 256 KB per widget, 48 widget per papan. - Pembaruan di tempat: memancarkan ulang widget dengan
nameyang sama akan mengganti bita, menaikkanrevision, menyiarkanboard.changed, dan tampilan aktif hanya memuat ulang iframe tersebut. - Pembekuan bita: kapabilitas yang diberikan terikat pada sha256 dari bita
widget. Mengubah bita mempertahankan pemberian
data/net/actionshanya jika revisi baru mendeklarasikan subset dari manifes yang diberikan; manifes yang diperluas akan meminta persetujuan operator kembali.
Widget menghosting konten; aplikasi MCP adalah salah satu jenis konten
Widget adalah primitif OpenClaw: sel papan bernama, tersemat, berukuran, dimiliki sesi, dengan catatan pemberian. Yang dirender di dalamnya adalah suatu jenis konten:html— dibuat agen melaluishow_widget, bita dalam penyimpanan papan.mcp-app— tampilan aplikasi MCP pihak ketiga (sumber dayaui://dari server yang dikonfigurasi) yang dihosting di dalam sel widget.
show_widget tetap sesingkat saat ini dan tidak pernah
perlu mengetahui bahwa spesifikasi MCP Apps tersedia.
Infrastruktur bersama di bawahnya (di sinilah penyederhanaan diterapkan):
- Satu host sandbox. Widget
htmldirender melalui pipeline tangguh yang sama dengan yang digunakan MCP Apps saat dirilis (iframe ganda pada origin sandbox khusus, CSP per widget yang dideklarasikan dan didekode dengan mekanisme gagal-tertutup), bukan melalui host iframe khusus kedua. Proksi menerima HTML berdasarkan nilai, sehingga konten lokal adalah kasus alami. - Satu model otorisasi. Jangkauan widget adalah daftar izin yang diberikan,
apa pun jenisnya: untuk widget
html, alat host; untuk widgetmcp-app, alat server yang terlihat oleh aplikasi (melalui mekanismeallowedAppToolNamesyang sudah ada, dibuat persisten per widget alih-alih per proses pencetakan). - Alat host untuk widget
html(diekspos melalui jembatan widget, diperiksa terhadap pemberian):openclaw.prompt.send— tingkat 2; dirutekan melalui komposer yang terlihat, dikonfirmasi pengguna kecuali telah diberikanopenclaw.state.emit— pemberitahuan sesi tingkat 1 (digabungkan, dibatasi ukurannya)openclaw.data.read— pengikatan hanya-baca berparameter (kumpulan RPC baca yang sudah ada dan masuk daftar izin), diselesaikan di sisi Gatewayopenclaw.cron.trigger— otomatisasi tingkat 3
net= CSP. Jangkauan jaringan menggunakan deklarasi CSP per widget yang sudah dirilis (connect-srcorigin) — widget cuaca yang memperbarui diri mengambil API-nya langsung dari sandbox, tanpa keterlibatan Gateway.- Pemberian. Widget yang tidak mendeklarasikan apa pun langsung dirender (tersandbox,
default-src 'none', pengiriman prompt dikonfirmasi satu per satu) — tingkat kepercayaan yang sama dengan widget obrolan sebaris saat ini. Alat/origin yang dideklarasikan menempatkan widget dalampendingpada papan: kartu placeholder mencantumkannya dalam bentuk yang mudah dibaca manusia dengan sekali ketuk Izinkan/Tolak. Pemberian berlaku per nama widget; untuk widgethtmlpemberian tersebut dibekukan berdasarkan bita (sha256), dan bita yang berubah mempertahankan pemberian hanya jika deklarasinya menyusut. - Shim pembuatan. Pembungkus dokumen menyuntikkan
window.openclaw.prompt,window.openclaw.state,window.openclaw.data, danwindow.openclaw.cronsebagai API pembuat yang stabil. Panggilan dasbor berbagi satu saluran permintaan yang terikat pada tiket tampilan; pelaporan ukuran dan token tema tetap menjadi notifikasi host yang terpisah.
Deklarasi kapabilitas Plugin
Plugin yang diaktifkan dapat memperluas host widget melaluidashboard.dataBindings
dan dashboard.actionVerbs dalam openclaw.plugin.json. ID lokal Plugin menjadi
nama pemberian yang diawali dengan ID Plugin, seperti workboard.cards.list dan
workboard.dispatch; % dan . dalam segmen ID Plugin di-escape agar
pemisahan Plugin/ID lokal yang berbeda tidak dapat mewarisi pemberian persisten yang sama. Selama
pendaftaran Plugin, OpenClaw memverifikasi bahwa setiap pengikatan menargetkan RPC
yang didaftarkan oleh Plugin yang sama dengan operator.read dan setiap tindakan menargetkan RPC
dengan operator.write; deklarasi yang tidak valid menggagalkan pemuatan Plugin. Registri yang telah divalidasi
hanya dibangun ulang saat terjadi perubahan siklus hidup Plugin, sementara pemberian widget
tetap berlaku per widget serta terikat pada bita dan revisi.
Residual yang dimodelkan: saluran data WebRTC
CSP sandbox memancarkan direktifwebrtc 'block' yang diusulkan, tetapi
kumpulan direktif CSP Chromium saat ini
tidak mengimplementasikannya. Oleh karena itu, widget yang dapat diprogram dapat menggunakan saluran data WebRTC
untuk lalu lintas keluar dalam Chromium saat ini. Residual yang sama sudah disertakan
untuk widget obrolan sebaris dan host MCP Apps pada main.
Kompromi yang diterima: OpenClaw tidak membatasi widget yang dapat diprogram berdasarkan
residu ini. Konten widget memperoleh akses ke data sensitif OpenClaw hanya melalui
kapabilitas data:read yang diberikan oleh operator dan dibekukan per byte, sementara
Permissions Policy sandbox memblokir akses kamera dan mikrofon. Pelindung API DOM
merupakan pertahanan berlapis dengan upaya terbaik, bukan batas keamanan, dan termasuk dalam
penguatan lanjutan.
Tampilan transkrip: satu kartu widget
Tampilan sebaris disatukan pada primitif widget. Saat hasil alat membawa UI — keluaranshow_widget atau hasil alat MCP dengan sumber daya aplikasi — sistem
mewujudkan widget sementara dengan nama otomatis (cakupan sesi, dipangkas), dan
transkrip merender satu kartu widget yang menentukan perilaku berdasarkan jenis konten.
Tampilan otomatis aplikasi MCP tetap persis seperti yang diharapkan spesifikasi (tanpa kerja model tambahan);
di baliknya, tampilan tersebut memang merupakan widget. Hal ini menghapus kasus khusus
mcpApp paralel dalam rendering obrolan (pembatasan permukaan, deduplikasi terpisah),
memberikan sarana penyematan yang sama kepada setiap UI sebaris, dan menjadikan registri
widget sebagai jalur utama untuk membuka kembali (rekonstruksi melalui pemindaian transkrip
tetap menjadi fallback untuk riwayat yang tidak pernah disematkan). Host mandiri hanya-baca
dengan tiket tumpang tindih dengan board sebagai permukaan persisten untuk membuka kembali —
kandidat konsolidasi yang akan dievaluasi dalam T6, bukan diasumsikan.
Komposisi: v1 menggunakan kedekatan kisi (widget chrome agen di sebelah widget aplikasi pada
satu tab). v2 menambahkan slot aplikasi yang dikelola host — HTML widget agen mendeklarasikan
wilayah slot dan host mengomposisikan tampilan aplikasi sebenarnya sebagai sandbox saudara.
Aplikasi tidak pernah dirender di dalam iframe agen: penyarangan akan merusak identitas
bridge dan memungkinkan overlay/clickjack pada UI aplikasi yang telah diberi izin, sehingga
slot tersebut merupakan kontrak tata letak, bukan sematan.
Widget yang bersumber dari server (aplikasi MCP yang disematkan)
Dengan host terpadu, menyematkan aplikasi MCP pihak ketiga hanyalah widget yang kontennya diambil dari server alih-alih disimpan:board_widgets menyimpan
deskriptor (serverName, toolName, uiResourceUri, toolCallId
asal + sessionKey) alih-alih byte HTML, dan board mencetak ulang lease
tampilan setelah TTL 10 menit giliran obrolan berakhir (mengambil ulang sumber daya
ui:// saat kedaluwarsa). Tampilan aplikasi MCP sebaris dalam obrolan mendapatkan
sarana Sematkan ke dasbor yang sama seperti widget agen. Tampilan yang dibuka kembali
saat ini hanya-baca secara sengaja; aplikasi tersemat yang harus tetap interaktif mendapatkan
grant tahan lama atas alat server yang terlihat oleh aplikasi (daftar izin eksplisit
ditampilkan kepada operator saat penyematan), yang dipisahkan dari proses pencetakan.
Sematan tanpa grant tetap hanya-baca — masih berguna untuk dasbor tampilan. v1 menyematkan
ke board sesi asal; penyematan lintas sesi memerlukan broker lease dan harus menunggu.
Koordinasikan dengan PR terbuka #109807 (perutean composer ui/message,
propagasi tema/ukuran).
Integrasi WorkBoard
Program integrasi WorkBoard mempertahankan kepemilikan kartu dan board oleh plugin sembari menghubungkan kembali kartu yang dikirim ke board sesinya melaluisessionKey dan runId yang sudah ada, mengekspos feed dan pengiriman WorkBoard melalui binding dan tindakan yang dideklarasikan plugin, serta mengomposisikan hasil tersebut dengan jenis widget html dan mcp-app yang sudah ada alih-alih memperkenalkan jenis widget khusus WorkBoard.
Tata letak: kisi fleksibel
12 kolom, tinggi baris tetap, pemadatan otomatis (gravitasi ke atas, bergeser saat diseret — semantik gridstack, diimplementasikan secara native; matematika kisi tetap murni dan bebas DOM). Status tata letak widget per tab:{ name, w (1-12), h (rows) } ditambah
urutan. Kosakata agen:
size:sm(3×3) ·md(6×4) ·lg(8×6) ·xl(12×8) ·full(tab satu widget)after: <widgetName>jangkar pengurutan opsional; jika dihilangkan = tambahkan di akhir- Pengguna bebas menyeret/mengubah ukuran; model urutan+ukuran yang sama dapat dipertukarkan dua arah.
Model data (DB per agen)
Tabel baru dalamagents/<agentId>/agent/openclaw-agent.sqlite
(memerlukan peningkatan versi skema DB agen — persetujuan operator diperlukan
sebelum perubahan ini diterapkan):
sessionKey. Menghapus sesi akan menghapus
baris board-nya. /new//reset tidak menyentuhnya.
Permukaan protokol
RPC (tabel metode inti, skema typebox dalamgateway-protocol):
board.get { sessionKey }→ tab + metadata widget (tanpa byte) —operator.readboard.update { sessionKey, ops[] }— CRUD/pengurutan ulang tab, pemindahan/perubahan ukuran/ penghapusan/pelepasan sematan widget, status dock, fokus tab —operator.writeboard.widget.put { sessionKey, name, html, manifest, placement }—operator.write(jalur alat agen dan jalur penyematan)board.widget.grant { sessionKey, name, decision }—operator.approvalsboard.event { ticket, payload }— penerimaan peristiwa status tingkat-1 yang terikat tiket; bentuk host tepercaya warisan{ sessionKey, widget, payload }tetap dipertahankan —operator.writeboard.prompt.authorize { ticket }— mengembalikan apakah pengiriman prompt yang terlihat masih memerlukan konfirmasi per klik —operator.readboard.data.read { ticket, bindingId, params? }— resolusi binding baca inti atau plugin aktif yang masuk daftar izin di sisi gateway —operator.readboard.action { ticket, action, ... }— pengiriman otomatisasi dengan grant yang tepat melalui jalur jalankan-sekarang cron yang sudah ada atau verba tindakan tervalidasi milik plugin aktif —operator.write
EVENT_SCOPE_GUARDS, cakupan baca):
board.changed { sessionKey, revision, widget? }— status persisten berubah; UI mengambil ulang (dan memuat ulang satu iframe saatwidgettersedia).board.command { sessionKey, command }— pengendalian UI sementara (agen mengganti tab yang terlihat, mengalihkan dock obrolan) — polaui.command.
Alat agen
Total tiga alat (inti, selalu terdaftar; rendering dibatasi berdasarkan kapabilitas klieninline-widgets seperti saat ini):
show_widget { title, widget_code, name?, pin?, size?, tab?, after?, capabilities? }— buat/perbarui berdasarkan nama;pinmenempatkannya pada board. Tanpaname/pin, perilakunya persis seperti saat ini (sebaris, sementara).dashboard { action, ... }— verba pengelolaan board:read,tab_create,tab_update,tab_delete,tabs_reorder,widget_move,widget_remove,unpin,focus_tab,set_chat_dock.- Alat
cronyang sudah ada mencakup tingkat otomatisasi; tidak diperlukan alat baru.
[dashboard] user clicked "Refresh" on widget weather (tab main).
Yang digantikan oleh ini
extensions/workspacesdihapus. Bersifat eksperimental,enabledByDefault: false, tidak pernah ada dalam rilis stabil (pertama kali muncul dalam versi beta 2026.7.2). Tidak ada migrasi; aturan doctor menghapus<stateDir>/workspaces/usang jika ada. Gagasan yang diambil: matematika kisi murni, model keamanan bridge (bootstrap port, pembatasan binding, batas laju), persetujuan yang dibekukan per byte.- Hosting widget dipindahkan dari
extensions/canvaske inti. Penyimpanan dokumen canvas, pembungkus dokumen, penyajian HTTP, dan alatshow_widgetmenjadi bagian inti (src/canvas/); plugin mempertahankan alat kontrol node-canvas (canvas) dan A2UI. PengiklananpluginSurfaceUrls["canvas"]dan jalur/__openclaw__/canvasmerupakan kontrak klien native yang telah dirilis dan tetap stabil. Sesi Discord mempertahankan varianshow_widgetmilik Discord.
Di luar sasaran (program ini)
- Berbagi board multi-pengguna/ACL (mendatang; akan hadir melalui berbagi sesi).
- Rendering board native macOS/iOS (tersedia di mana pun Control UI disematkan; jalur widget sebaris tidak berubah).
- Widget data bawaan (kartu sesi/penggunaan/cron) — bridge kapabilitas ditambah widget buatan agen mencakup v1; registri jenis bawaan dapat ditambahkan nanti.
Rencana implementasi
Worktree independen, dibuat dengan Codex, direview+diterapkan secara berurutan. Terapkan-lalu-perbaiki.
Validasi sesuai aturan repo: vitest terfokus secara lokal, pemeriksaan lengkap pada
Crabbox/Testbox,
$autoreview sebelum setiap penerapan, bukti langsung untuk T6.