Phương tiện để sai agent AI kiểm thử website giùm

Mình làm website, mỗi lần làm xong một tính năng mới, hay sửa một tính năng bị lỗi, sẽ phải mở website, thao tác lại các bước để xem "chắc ăn" chưa. Nhiều khi việc sửa code thì dễ, nhanh nhưng việc test thủ công kiểu này thì lâu, nhất là những tính năng nằm trong sâu, phải đi qua nhiều bước mới vươn tới. Bởi vậy tìm cách kết hợp với agent AI cho nó gánh bớt.

Do mình chủ yếu làm việc bằng truy cập từ xa (xem bài "Làm việc từ xa bằng máy tính ở nhà"), dùng Terminal, nên hầu hết các giải pháp "dùng AI agent điều khiển trình duyệt" ngoài kia là không phù hợp với mình. Cụ thể:

  • Mình luôn dùng agent AI trên Terminal. Các agent trong VS Code, Zed mình không muốn đụng đến.

  • Khi làm việc kiểu truy cập từ xa thì trình duyệt và agent chạy trên hai máy khác nhau nên đa số giải pháp (agent tích hợp trong code editor) cũng không phù hợp.

...

Define UI comprising keyboard Shortcut in Blueprint for modern GTK apps

In previous posts, ["Define UI comprising Dropdown in Blueprint for modern GTK apps"][dropdown-post] and ["Define UI comprising ListView in Blueprint for modern GTK apps"][listview-post], I presented how to use list widgets in [Blueprint][blueprint]. Now we look at a different, but more compact topic, the keyboard shortcut.

In a desktop app, the user is expected to do a lot of work with the keyboard alone, not always reaching for the mouse. So a good app should have many keyboard shortcuts. For example, a Ctrl+V to paste, a Ctrl+S to save, an F1 to show help, etc. Most GUI toolkits have built-in support for this. GTK is no exception. There are two ways to assign a keyboard shortcut to an action in GTK 4:

  • The simplest one is the application's accelerator, set via [gtk_application_set_accels_for_action()][set-accels]. You define the action on the application (with the app. prefix), then call that function with a list of accelerator strings. But this is not declarative, you have to write code.
  • A more flexible way is to use a [Gtk.ShortcutController][shortcut-controller], to which you add one or more [Gtk.Shortcut][shortcut] objects. Each Shortcut binds a trigger (a key combination) to an action. This is what we will learn in this post, because it is declarative and we can describe the shortcut in the Blueprint file alongside the rest of the UI.
...

Dựng container Incus để chạy GitHub runner

Từ khi phong trào vibe code ra đời, dịch vụ GitHub thường bị quá tải (do sự khai thác quá mức từ các agent AI), cao điểm là cách đây mấy hôm, quy trình CI/CD ở công ty mình bị tê liệt khi GitHub không thể cấp phát các runner để chạy CI/CD. May sao công ty dùng server bare-metal, còn dư công suất nên mình ngắt ra một phần, dựng các container Incus để chạy runner self-hosted cho GitHub Actions. Bài này sẽ hướng dẫn cách setup.

Tại sao là Incus?

Incus là chương trình quản lý tạo và chạy container hoặc máy ảo. Mình cần có nhiều GitHub Runner để chạy được nhiều job CI/CD cùng lúc. Giải pháp là chia nhỏ máy thật ra thành nhiều "máy ảo", và cài GitHub Runner trong đó. Tuy nhiên, tạo máy ảo virtual machine như trên QEMU, VirtualBox thì hơi cồng kềnh, một "system container" sẽ gọn nhẹ hơn. Nói về container, có lẽ cái tên Docker được biết đến rộng rãi nhất, nhưng nó không phải là giải pháp container duy nhất, lại càng không phải cái đầu tiên. Mình dùng Incus vì mình cần "system container", là loại container chạy được systemd bên trong để quản lý nhiều dịch vụ mà không cần sửa đổi gì. Nói thêm một chút, loại container được tạo bởi Docker là "application container", hướng đến đóng gói một ứng dụng cụ thể nên nó không thể chạy systemd bên trong và khi dùng nó để chạy các phần mềm database như Postgres, Redis, người ta phải dùng thêm mấy lệnh "của nợ" như sau:

...

How to logout a Linux desktop session from command line

I often go out then remotely access to my home PC to work. Sometimes I use that PC at home, running a desktop session then forget to logout when leaving home. At a consequence, many programs run and waste the CPU, RAM. How to logout that session when I'm not at home?

There is a command to do that, loginctl. So, from the coffee shop, I just SSH to my home PC, then run this:

loginctl terminate-user $USER
...

Make Helix clipboard-copy work when running in byobu

Though I often use [Zellij] as terminal multiplexer when working on remote machine, sometimes I need to switch to [byobu] for its feature of keeping session alive when I disconnect SSH.

One inconvenience with byobu is that, when running Helix inside it, the "copy to clipboard" feature (press Space then y) stops working. Only recently did I learn that one of the backends that Helix uses for the clipboard feature is "tmux", the same software under byobu's hood. It means that, when running in byobu, Helix should still be able to do "copy to clipboard", it is just a configuration matter that byobu disable the feature.

Here is how to make the "copy" works again, open ~/.config/byobu/profile.tmux file and add these lines:

...

journald-send - Library to help write logs to journald, for Python

In the last April, I made [journald-send], to serve as replacement for [systemd-python], for folks who want to write logs to journald, using native protocol.

It is a partial replacement, because it only offers the "write" part, not "read". That's enough because most of applications which want to talk with journald just need to "write". I made [journald-send] out of the frustration that systemd-python development seems to be stuck, the last release was on the beginning of 2023, when it is 2026 now, and the compatibility with Python 3.14 is uncertain. Even after I contributed some code to modernize the Python project structure, the core developers still seems to not rush to make a release.

I wrote [jounald-send] in Rust, aiming for Python 3.14 free-threaded (No GIL) mode. Because I only need to support "write" operation, I decide not to depend on the C libsystemd, and go further by using Rust pure libraries ([rustix] and [memfd]) to talk with Linux API. I learnt from [tracing-journald] for how to prepare data for journald protocol and which steps to do with the sockets. The difference is that [tracing-journald] is using libc and I use [rustix], [memfd].

After finishing [journald-send], I updated my other libraries [chameleon-log], [structlog-journald] to use journald-send under the hood. [chameleon-log] is for integrating [logbook] and [structlog-journald] is for integrating with [structlog].

...

Define UI comprising ListView in Blueprint for modern GTK apps

In a previous post, ["Define UI comprising Dropdown in Blueprint for modern GTK apps"][dropdown-post], I presented how to use [DropDown][dropdown] in [Blueprint][blueprint]. Now we go with a bit more complex example, with ListView widget.

This is the UI where ListView is used, in my [CoBang][cobang] app:

WiFi list

It shows a list of WiFi network config, for which user will pick to generate QR code. The list is accompanied with a search box, via which user will type part of Wi-Fi name to narrow down the list, to quickly find the needed Wi-Fi network.

...

Define UI comprising Dropdown in Blueprint for modern GTK apps

GTK is one of the GUI toolkits for building Linux desktop apps, notable for its modern visual look, and with some advanced developer experience features, like Inspector.

But one of the things that is still old-fashioned is its support for declarative UI. GTK allows developer to describe the UI separately from application code, but the language is XML which is too verbose, comparing to QT's QML or Slint. Fortunately, there is an new language, Blueprint, to describe UI for GTK app, which brings the same taste of QML, Slint to the table. But Blueprint is still young, not integrated to GTK yet (the files written in Blueprint must be compiled to Gtk.Builder XML) and the documentation is not rich enough.

This post shows you how to use Dropdown or other list widgets (like ListView, GridView) in Blueprint. The example use case and code is drawn from my application, CoBang.

List widgets follow Model-View-Controller pattern, to dislay a list of data with dynamic length. The widget is not used alone, but with other non-display components from GTK library:

...


Set a terminal emulator to be default for Ubuntu 25.04+

Ubuntu comes with a default terminal emulator, GNOME Terminal. But due to the limit of the underlying vte, many users don't want to use it. If you want to set a different program as default terminal, so that you can invoke it with Ctrl + Alt + T, here is how to do it.

Determine the desktop file of your terminal, by searching in /usr/share/applications/ or ~/.local/share/applications/. For example, kitty has one at ~/.local/share/applications/kitty.desktop, Ghostty has one at /usr/share/applications/com.mitchellh.ghostty.desktop.

Edit the ~/.config/xdg-terminals.list file (create it if it does not exist). Add the name of the desktop file at the top. For example, here is mine:

...