Khám phá Learn Stream About Jokes
INSIDER Tony's Friends — Insider — ~2 playbook/tuần, Discord riêng, tài nguyên dựng sẵn Tham gia →
Bài viết

Canary: lớp verify cho autonomous coding

Một autonomous harness lo việc build. Nhưng ai kiểm tra cái nó vừa build, và lần sau mình chạy lại bằng gì? Canary là lớp QA biến mỗi lần agent thử thành một Playwright script chạy lại được.

Canary: lớp verify cho autonomous coding

Agent build được feature là một nửa câu chuyện. Nửa còn lại là: ai kiểm tra flow đó, và lần sau mình chạy lại bằng gì?

Ở bài AI harness là gì, mình nói harness (bộ khung điều khiển AI) là lớp phần mềm làm cho model thật sự làm được việc: đọc file, chạy lệnh, giữ context, hỏi quyền, gọi tool, rồi đi qua nhiều vòng sửa lỗi. Qua bài Harness ép kỷ luật, không thay kỹ sư, câu chuyện đi thêm một bước: một harness tốt có thể ép agent đi theo quy trình kỹ thuật đàng hoàng, từ ý tưởng, PRD, chia việc, review, tới merge.

Nhưng nếu nhìn thẳng vào vòng lặp đó, còn một khoảng trống khá rõ. Agent có thể build một thay đổi từ đầu tới cuối. Vậy ai kiểm tra cái nó vừa build? Và quan trọng hơn: nếu hôm nay agent click qua một flow rồi báo “works”, ngày mai mình chạy lại bằng gì?

Đó là chỗ Canary đứng vào. Nó là một harness mã nguồn mở (MIT). Tagline của nó là “QA harness built for Claude Code”, nhưng mình nghĩ cách hiểu đúng hơn là: Canary là lớp verify (kiểm chứng) cho autonomous coding loop. Không chỉ để agent mở trình duyệt rồi bấm thử vài cái, mà để biến lần bấm thử đó thành bằng chứng và script có thể chạy lại.

QA không nên là một lần click rồi tin

Vấn đề của browser QA với agent không nằm ở chuyện agent có biết click hay không. Playwright đã giải bài toán điều khiển browser từ lâu. Vấn đề là agent thường làm một việc rất “mù”: nó đoán selector (cách chọn phần tử), click, đọc DOM, rồi nếu flow chạy được thì kết luận xong. Lần chạy đó có thể hữu ích cho con người đang debug, nhưng rất khó tái sử dụng.

Canary đổi trọng tâm từ “agent đi test giùm mình” sang “agent khám phá flow một lần, rồi để lại thứ mình chạy lại được”. Core promise của nó khá gọn: agent làm QA và trả về cả report.html cho người đọc lẫn một Playwright script (kịch bản tự động hóa trình duyệt) có thể tái chạy.

Điểm này nghe nhỏ, nhưng nó là khác biệt giữa một agent run mờ mờ và một test artifact (hiện vật kiểm thử) thật sự. Nếu chỉ có “agent đã thử và thấy ổn”, mình vẫn phải tin vào một lần suy luận. Nếu có script, trace, video, HAR, console log, screenshot từng bước, thì mình có bằng chứng để đọc, và CI (hệ thống chạy kiểm thử tự động) có thứ để chạy lại mà không cần tốn thêm inference của model. Khám phá flow một lần, chạy lại mãi về sau — đó mới là phần đáng giá.

Ba công cụ, một runtime

Canary có ba bề mặt dùng chính. canary là orchestrator CLI (CLI điều phối), dùng để ghi lại session QA có capture (ghi bằng chứng) và render report. canary-browser là engine CLI (CLI điều khiển browser), dùng cho automation một lần, không tập trung vào recording. canary-viewer, hay @usecanary/ui, là viewer (trình xem) local để mở lại các session đã ghi.

Điểm đáng chú ý là hai CLI không tự mỗi cái kéo một browser runtime riêng. Chúng dùng chung một daemon (tiến trình nền) Node chạy dài, bên trong sở hữu Playwright và QuickJS sandbox. Daemon tự khởi động khi cần, nên người dùng không phải tự nhớ bật server nào trước.

Luồng của nó đại khái như vầy:

canary run ... --session ...
canary-browser run ...

daemon RPC

Playwright

Thiết kế này quan trọng vì Canary không chỉ là một wrapper mỏng quanh Playwright. Nó là một harness đúng nghĩa: có runtime, có protocol, có sandbox, có capture pipeline, có report, và có cách nói chuyện với agent.

Observe first, then act

Một chi tiết mình thích trong Canary là nó không bắt agent click bằng cách đoán CSS selector từ HTML thô. Agent “nhìn” page qua page.snapshotForAI(). Hàm này trả về một aria outline (dàn ý theo accessibility tree): role, accessible name, và các marker [ref] để trỏ tới phần tử.

Ví dụ ý tưởng của nó gần như vầy:

const snapshot = await page.snapshotForAI();
// button "Sign in" [ref=e12]
// textbox "Email" [ref=e8]
// link "Forgot password?" [ref=e15]

Khi nhìn page theo ngữ nghĩa như vậy, agent có cơ hội chọn selector bền hơn: getByRole, getByText, hoặc một ref có ý nghĩa, thay vì đoán .btn-primary:nth-child(2). Đây là kiểu discipline mà mình đã nói ở bài trước: harness không làm model thông minh một cách ma thuật, nhưng nó ép model làm việc trong một hình dạng tốt hơn.

“Observe first, then act” nghe giống lời khuyên đơn giản, nhưng với agentic QA nó là một ranh giới lớn. Trước khi bấm, agent phải quan sát page theo thứ mà người dùng thật sự thấy: nút gì, form gì, text gì, trạng thái gì. QA vì vậy bớt giống scraping DOM và gần hơn với kiểm tra workflow.

Sandbox là phần làm mình yên tâm hơn

Agent quan sát page theo ngữ nghĩa và lái browser từ trong sandbox, bị chặn khỏi filesystem, node và network của host

Canary cho script chạy trong QuickJS WASM sandbox (hộp cát bảo vệ). Bên trong sandbox, agent có full Playwright Page API để điều khiển browser, nhưng không có Node, không có filesystem, không có require hay import, và không có direct fetch. Nếu cần networking, page tự làm networking như một browser bình thường.

Đây là boundary (ranh giới an toàn) rất thực tế. Agent được phép lái một browser thật, nhưng không được tự tiện chạm vào host machine. Nó không thể đọc file trong repo qua filesystem, không thể import một package bất kỳ, không thể mở network riêng ngoài page context.

Sandbox còn bị giới hạn CPU, wall-clock và memory. Infinite loop thì abort. Với một QA harness cho agent, mình thấy đây không phải chi tiết phụ. Nếu mình cho agent quyền chạy browser để kiểm thử app, mình muốn quyền đó được đóng khung rõ ràng. Browser là công cụ, không phải cửa sau vào máy dev.

Report là để người đọc, script là để hệ thống chạy lại

Canary bật capture mặc định. Mỗi session ghi lại Playwright trace (bản ghi lại từng bước), video replay (video phát lại), network HAR (bản ghi request/response), console logs, và screenshot theo từng step. Tất cả nằm trong ~/.canary/sessions/<id>/, kèm một report.html tự chứa.

Tự chứa ở đây là điểm rất tiện: không cần server, không cần viewer riêng, không cần “à để mình cài thêm cái này mới mở được”. Mình có thể mở file, gửi cho người khác, hoặc commit vào đâu đó nếu team muốn lưu bằng chứng cho một thay đổi quan trọng.

Nhưng phần đáng giá nhất không phải chỉ là report đẹp. Canary decode full Playwright trace ra đúng các call mà agent đã gọi: goto, waitForSelector, evaluate, screenshot, kèm params và timing. Từ đó nó tạo ra một Playwright script thật, không phải transcript văn xuôi.

Đây là chỗ QA agent trở nên có ích lâu dài. Lần đầu agent dùng suy luận để tìm flow cần test, nhưng sau khi flow đã được khám phá, lần sau CI chỉ cần chạy script — không cần model suy luận lại, không cần agent “nhớ” hôm trước nó đã làm gì, cũng không cần con người ngồi viết lại test từ report.

Verify nên bắt đầu từ diff, không bắt đầu từ browser

Trái tim của Canary, theo mình, là workflow canary-verify. Nó không bắt đầu bằng câu “mở app rồi click thử đi”. Nó bắt đầu bằng git diff (phần thay đổi trong code). Agent đọc diff, rồi map file thay đổi sang user-facing workflow (luồng người dùng) như sign-up, checkout, login, onboarding, chứ không map sang file.

Đó là một khác biệt quan trọng. Người dùng không care file nào đổi, người dùng care flow nào bị ảnh hưởng. Một thay đổi trong component, route, state management, hoặc API client có thể cùng đụng tới một workflow. Harness bắt agent suy nghĩ theo hướng đó trước khi mở browser.

Plan của Canary cũng không phải “test everything”. Nó tạo QA plan theo P0/P1/P2: entry URL là gì, cần check điều kiện nào, text nào phải visible, URL nào phải đúng, state nào phải giữ, console có error hay không, và file nào trong diff làm flow đó rủi ro. Nếu diff chỉ là refactor thuần, type, config, hoặc thứ không chạm UI, nó có thể nói “không cần browser QA” thay vì bịa ra một flow cho có.

Luật hay nhất ở đây là: suggest first, record second. Agent đề xuất plan trước, mình duyệt, rồi nó mới record. Canary cũng giữ repo read-only trong verify flow: nó đọc diff, nhưng không stage, không commit, không sửa source. QA ở đây là lớp kiểm chứng, không phải một agent thứ hai lén sửa code sau lưng mình.

Một loop lý tưởng vì vậy nhìn như vầy:

agent builds

agent reads diff

agent proposes QA plan

human approves

Canary records browser QA

report.html + reproducible Playwright script

CI keeps running the script

Đây là cách mình muốn autonomous coding lớn lên: không chỉ tự build, mà tự để lại bằng chứng có thể kiểm lại.

Built for agents nghĩa là nó biết giải thích cho agent

Canary được đóng gói như plugin (gói mở rộng) cho Claude Code, Cursor, và Codex. Nó có skills (kỹ năng hướng dẫn agent), subagents, và slash commands như /canary:verify, /canary:session, /canary:run, /canary:review. Nói cách khác, nó không chỉ có CLI cho người; nó có “ngôn ngữ vận hành” cho agent.

Thậm chí nếu không dùng plugin, mình có thể bảo agent chạy canary --help. Help output được viết như một usage guide cho LLM đọc được, không chỉ là danh sách flag ngắn ngủn cho người đã biết tool. Đây là một hướng thiết kế mình nghĩ sẽ ngày càng phổ biến: tool không chỉ cần API tốt, mà cần self-documenting interface (giao diện tự giải thích) cho agent.

Với harness, documentation không còn chỉ dành cho developer. Nó là context mà agent sẽ đọc trong lúc làm việc. Nếu doc mơ hồ, agent sẽ đoán. Nếu help output chỉ nói “usage: command [options]”, agent vẫn phải tự suy luận phần còn lại. Canary chọn cách nói rõ workflow, boundary, và expectation ngay trong tool.

Cùng một kỷ luật, lần này cho QA

Nếu hai bài trước của mình là về harness như lớp ép kỷ luật cho build loop, thì Canary cho thấy cùng nguyên tắc đó áp vào QA. Agent không nên chỉ nói “mình đã test”. Nó nên để lại dấu vết: report cho người đọc, trace cho debug, video cho tái hiện, HAR cho network, console log cho lỗi runtime, screenshot cho từng bước, và script cho CI.

Điểm mình thấy đáng giá nhất là Canary không bắt mình chọn giữa hai thái cực. Một bên là agent chạy một phiên kiểm thử opaque, xong rồi biến mất. Bên kia là raw Playwright script mà con người phải tự viết và bảo trì từ đầu. Canary đứng ở giữa: để agent dùng khả năng suy luận để khám phá flow, nhưng kết quả cuối cùng là artifact máy móc có thể chạy lại.

Đó là đúng tinh thần “harness ép kỷ luật, không thay kỹ sư”. Mình vẫn quyết định plan có hợp lý không, vẫn review report, vẫn chọn script nào đáng đưa vào CI. Nhưng harness làm cho agent không được dừng ở lời hứa “works on my machine”.

Với autonomous coding, câu hỏi không còn chỉ là “agent có build được không?”. Câu hỏi trưởng thành hơn là “sau khi build xong, hệ thống có để lại bằng chứng đủ tốt để team tin và chạy lại không?”. Canary là một câu trả lời khá rõ cho phần đó.

Bạn thì sao: trong workflow hiện tại của bạn, agent sau khi code xong đang QA bằng niềm tin, bằng screenshot rời rạc, hay đã để lại được một script chạy lại trong CI?

#ai-harness #autonomous-coding #qa #playwright #claude-code #ai-workflows

Bài viết liên quan

Harness ép kỷ luật, không thay kỹ sư

idea

Giá trị của một harness cho autonomous coding không nằm ở chỗ 'AI tự code', mà ở chỗ nó bắt mình đi qua những bước một kỹ sư tốt thường bỏ qua khi đang vội. Cái thang đó mới là phần portable.

Làm chồng bấy lâu, đến hôm nọ mình mới thấy mình có ích với vợ

idea

Ở chung nhà với vợ mỗi ngày, mình vẫn không thấy được phần mình có ích cho vợ — cho đến một sáng cafe với Claude Code và 30 phút rất vụn.

0:00

Chia sẻ ảnh

Bắt đầu gõ để tìm kiếm...