Giải thích Pi Durable: dựng agent always-on với model chạy local
Pi Durable là harness có checkpoint giúp agent always-on chạy tiếp sau crash: kiến trúc, sáu bước khởi tạo, demo llama.cpp và resume từ SQLite.
✓ Đã duyệt độc lập · cập nhật 20/10/2026 · 30 min
1. Vì sao cần một video về Pi Durable, và lộ trình hôm nay
Alejandro chào mọi người và giới thiệu chủ đề: Pi Durable, và cách dùng nó để tạo ra những ứng dụng agent always-on của riêng bạn. Anh thừa nhận từ lúc ra mắt, mọi thứ quanh Pi Durable hơi hỗn loạn: người ta chưa rõ phải dùng nó thế nào, và nó khác gì so với Pi coding agent chẳng hạn. Theo bài giới thiệu chính thức của Earendil, Pi Durable được phát hành ngày 01/10/2026 dưới dạng một package thử nghiệm, cùng lúc với Pi 1.0 (earendil.com/posts/pi-durable).
Mục tiêu của video là làm rõ tất cả: cho bạn thấy cách dùng nó, bạn có thể build được gì với nó, và đi qua một chút về kiến trúc, để bạn tự dựng được ứng dụng của mình với các open model trên Hugging Face.
Lộ trình gồm bốn phần. Đầu tiên là định nghĩa Pi Durable là gì và làm được gì. Sau đó là một cái nhìn rất nhanh về chỗ đứng của Pi Durable trong toàn bộ hệ sinh thái Pi, và nó so với Pi coding agent ra sao. Tiếp theo là kiến trúc của một ứng dụng dùng Pi Durable, để bạn hình dung được cách dựng agent always-on của riêng mình với bất kỳ model nào bạn muốn. Nhờ vậy bạn không bị trói vào model của OpenAI, ví dụ với OpenAI Dots, hay vào model của xAI với Grok Bot. Bạn có thể dựng ứng dụng của mình với bất kỳ model nào.

Phần cuối, Alejandro cho xem một script thật chạy trên Pi Durable: một agent rất tối giản. Về cơ bản nó chỉ là một script để bày ra API của harness, cho bạn thấy thật sự có thể dùng nó thế nào để tạo ứng dụng của riêng mình. Mục đích là để bạn có trực giác rõ ràng về việc nó đang làm gì phía sau, và cách nó dùng storage để tạo trạng thái bền vững (persistent state) cho agent, nhờ đó agent luôn có thể tiếp tục đúng chỗ nó đã dừng. Rồi anh bắt đầu luôn, từ định nghĩa của Pi Durable.
2. Định nghĩa: một agent harness sống sót qua crash
Alejandro cho rằng định nghĩa là chỗ dễ và đơn giản nhất để bắt đầu, và anh sẽ đi kèm một ví dụ để dễ hình dung chuyện gì đang diễn ra. Định nghĩa đơn giản nhất anh nghĩ ra được là: một agent harness được thiết kế để sống sót qua crash và gián đoạn một cách đáng tin cậy.

Nói cách khác, nếu agent đang làm gì đó và bị dừng giữa chừng một thao tác thì nó vẫn đi tiếp được. Thông thường bạn sẽ chạy nó như một daemon chạy nền, kiểu một background process trên server hay trên máy của bạn. Nếu tới một lúc nào đó process crash hoặc hỏng, hệ thống sẽ bật process đó lên lại, và agent tiếp tục đúng tại điểm nó đã dừng.
Điều quan trọng là việc này được làm một cách an toàn, kể cả khi gián đoạn xảy ra ngay giữa một tool call, hay giữa một tool call nhạy cảm. Theo Alejandro, chính những lúc như vậy là lúc tính chất này quan trọng nhất. Để dễ hình dung hơn, anh đưa ra một ví dụ.
3. Ví dụ gửi năm email với Pi coding agent
Giả sử bạn đang nói chuyện với một agent, cụ thể là Pi coding agent thông thường. Ví dụ này sẽ cho thấy sự khác nhau giữa harness của Pi coding agent và harness mới Pi Durable.
Với harness của Pi coding agent: bạn giao cho nó một task, bạn muốn gửi vài email cho một số khách hàng. Người dùng gửi prompt "hey send my emails". Agent nhỏ của bạn sẽ nói "okay" và gọi một tool, có thể tool tên là send email, hoặc nó làm qua bash hay cách khác. Ý chính là Pi agent sẽ gọi một tool. Việc tiếp theo là tool call đó được nhận và bắt đầu thực thi.
Giả sử có năm email cần gửi. Agent gửi được bốn email, và tới email cuối cùng thì crash. Service sập, ứng dụng tắt, hệ thống phải bật nó lên lại.
Với coding agent bình thường, thứ bạn đã quen, chuyện này được lưu vào file JSONL theo cách sau. File JSONL chính là session file. Nếu bạn chưa quen với cách Pi coding agent lưu session, Alejandro gợi ý xem một video khác của anh, nơi anh giải thích session file hoạt động thế nào và cách Pi coding agent lưu session trong loại file cho phép tạo cấu trúc cây (tree structure) trong session, để bạn có thể rẽ nhánh (branch off) từ nhiều điểm khác nhau. Anh nói thêm rằng chuyện đó rất vui và rất thú vị.
Harness của Pi coding agent lưu như sau. Task bạn gửi, "send emails", là một user message. Tool call là một AI message, hay assistant message, mà bản thân nó là một tool call. Vì máy đã bắt đầu thực thi tool call, lẽ ra sau đó phải có một tool response. Ở loại agent này, mỗi khi nhận một tool call, lịch sử hội thoại luôn đòi một tool response ngay sau nó. Thực tế, nếu bạn gửi một loại message khác ngay sau tool call, LLM sẽ hỏng, không thể trả lời bạn. Các API của LLM bắt buộc bạn phải gửi tool response sau tool call.

Vấn đề ở đây là không hề có tool response, vì tool call chưa bao giờ kết thúc. Nhưng nó đã làm được một phần việc: bốn email đã được gửi, chỉ còn một email chưa gửi. Nếu bạn khởi động lại coding agent, nó sẽ khởi động trên một tool call bị cắt cụt. Thông thường Pi, hay các coding agent khác, sẽ gửi một tool response giả báo rằng có lỗi, để agent biết tool call vừa rồi gặp lỗi. Rồi từ đó thường bạn phải tự tìm hiểu chuyện gì đã xảy ra.
Bạn sẽ phải gửi một message "continue". Tức là, với vai trò người dùng, bạn phải khởi động lại agent, gửi "continue", và tự tìm xem trong lúc đó đã xảy ra gì. Đó là điều xảy ra nếu bạn dùng coding agent.
4. Cùng ví dụ đó với Pi Durable: task, checkpoint và tự chạy tiếp
Khác biệt của Pi Durable nằm đúng ở chỗ này: toàn bộ phần vừa kể được xử lý tự động. Alejandro đổi sang bút màu xanh cho cột Durable.
Với Durable, khi bạn gửi "send emails", yêu cầu đó được lưu thành một task trong harness, và task đó sẽ có nhiều checkpoint bên trong. Khi agent trả lời bằng một tool call, tool call đó cũng được lưu bền vững (persistently) vào hệ thống storage. Thông thường Pi Durable đi kèm storage dạng cơ sở dữ liệu SQLite chạy cục bộ trên máy, hoặc một loạt file JSONL, hoặc in-memory. Dĩ nhiên in-memory thì không bền vững; memory chủ yếu dùng để thử nghiệm.
Điều xảy ra là harness lưu checkpoint cho những gì nó làm. Nếu tool được xử lý đúng cách, lý tưởng là nó có checkpoint cho bốn email đã gửi. Và kể cả khi không lưu checkpoint cho từng email, nó vẫn lưu checkpoint về việc nó đã bắt đầu một tool call, đã bắt đầu một phần việc, và rằng nó chưa hoàn tất tool call đó.

Thông thường bạn sẽ chạy cái này như một process trên server hay tương tự, vì theo Alejandro, lý tưởng là nghĩ về Durable như một hệ thống vận hành các trợ lý always-on. Trong đầu anh, đó là chỗ Durable hữu ích nhất. Daemon, hay hệ thống của bạn, sẽ khởi động lại process. Process đọc lại trạng thái, tức các task và mọi checkpoint, từ cơ sở dữ liệu SQLite hoặc từ các file JSONL, rồi cứ thế tiếp tục agent từ đúng điểm nó đã dừng, mà bạn không cần gửi "continue".
Đó là hai khác biệt chính. Một: nó lưu checkpoint đáng tin cậy cho từng thao tác. Hai: nó cứ thế tiếp tục với trạng thái có trong các checkpoint ấy. Về cơ bản đó là khác biệt chính giữa Pi coding agent và Pi Durable.
Phần mô tả video có ghi thêm hai lưu ý: các API vẫn đang thử nghiệm và có thể thay đổi, và việc chạy lại tool một cách an toàn (tool replay safety) cũng như việc khởi động lại host process vẫn là trách nhiệm của ứng dụng.
5. Pi Durable không phải một CLI mới
Tới đây có thể bạn sẽ thắc mắc: hay quá, vậy có nghĩa là giờ mình chỉ cần mở command line, thay vì gõ pi thì gõ pi durable, và mình sẽ có một Pi coding agent không bao giờ hỏng? Alejandro trả lời thẳng: không, Pi Durable không phải như vậy. Anh giải thích giao diện người dùng thực sự của Pi Durable là gì.
Nếu điểm tiếp xúc chính của bạn với Pi tới giờ là qua Pi coding agent, có lẽ bạn đang hơi lạc về chuyện gì đang diễn ra với Pi Durable. Có thể bạn đã nghe nhiều người nói kiểu: Pi Durable tuyệt lắm, giờ có thể cho nó làm các task dài (long-running task) một cách đáng tin cậy, và những thứ tương tự. Rồi bạn tự hỏi: mình phải làm điều đó thế nào? Có một CLI tool nào, hay một coding agent nào chạy trên Pi Durable không? Câu trả lời là không.
Pi Durable không phải một ứng dụng như Pi coding agent. Cách nhìn tốt hơn là coi nó như một building block cho coding assistant của riêng bạn, hay cho các agent bạn sẽ build. Lý tưởng là nó dùng để vận hành các agent được thiết kế để luôn bật (always on). Ví dụ là thế hệ agent mới như OpenAI Dots, Muse của Meta hay Grok Bot: những agent sống trên một server và được kỳ vọng tiếp tục làm việc trong lúc bạn làm việc khác, sao cho chúng chạy ổn định kể cả khi bạn không ngồi trước máy tính.
Nó đặc biệt hữu ích khi bạn build các agent có nhiều đầu vào khác nhau, nhiều gateway khác nhau. Ví dụ, nếu bạn tương tác với loại agent này qua Telegram, qua Slack hay qua email, bạn không ngồi trước máy tính suốt để đảm bảo agent không hỏng trong lúc nó đang chạy một việc gì đó. Đó là chỗ Pi Durable hữu ích: nó ở đó để giúp bạn build những hệ thống như vậy một cách đáng tin cậy, và nó làm việc đó theo một cách rất thẳng.
6. Kiến trúc của Pi: coding agent, Pi Harness và Pi AI
Để thấy Pi Durable nằm ở đâu trong toàn bộ kiến trúc của Pi, Alejandro đi rất nhanh qua kiến trúc của Pi coding agent thông thường.
Pi coding agent chạy trên Pi Harness; đây là hai package khác nhau trong project Pi. Pi Harness về bản chất là agent loop: nó xử lý toàn bộ session, việc gom các tool lại với nhau, cách chạy tool, và mọi thứ tương tự.
Đến lượt mình, Pi Harness chạy trên một package tên là AI (Pi AI), đóng vai trung gian giữa Pi và tất cả các model. Tóm lại, Pi coding agent dựa vào harness, thứ giống như cái loop thực sự đang chạy, còn Pi AI là phần tích hợp thực sự với các model.
Pi coding agent mới là ứng dụng. Đây là nơi có giao diện terminal (terminal user interface), nơi định nghĩa system prompt, nơi định nghĩa extension layer, và những thứ tương tự. Tất cả những phần đó nằm trong Pi coding agent: đó là các công cụ, hay nói đúng hơn là ứng dụng thực sự mà bạn dùng, dựa trên hai package còn lại.
7. Pi Durable nằm ở tầng harness
Vậy Pi Durable nằm ở tầng nào? Câu trả lời của Alejandro: Pi Durable là một thứ thay thế cho Pi Harness. Nó là một harness khác, và cũng dựa trên Pi AI.
Như vậy nó dùng cùng phần tích hợp với cùng các model AI, cùng những model call đáng tin cậy với prompt caching và mọi thứ mà Pi AI xử lý rất chính xác và rất gọn. Nhưng Pi Durable là một gốc khác, một trong những package lõi khác, dùng để vận hành những thứ khác. Bản thân nó không phải ứng dụng.

Harness(). Phía trái vẫn thấy Pi coding agent với TUI, system prompt và extension.Theo Alejandro, một cách hay để nhìn những gì Durable thật sự cung cấp là: nó cung cấp một harness class, và về cơ bản chỉ có vậy. Dĩ nhiên còn nhiều thứ khác, nhưng đó là cách nghĩ dễ hiểu. Đó là một harness class với một API rất gọn, dùng để tạo conversation và để query. Sau đó bạn gửi task vào harness, và các task ấy chạy đáng tin cậy vì harness sẽ lo cho chúng.
Về cơ bản, đây là một lựa chọn song song, hay thay thế, cho việc bạn chạy Pi Harness qua RPC chẳng hạn, hoặc import Pi Harness qua Pi SDK. Bạn làm đúng những việc đó, nhưng với durable harness. Nếu bạn đang build một coding agent hay thứ tương tự, có thể bạn sẽ muốn dùng SDK của Pi Harness thông thường.
Còn nếu bạn tạo một agent làm việc ở chế độ nền (in the background), có những task chạy lâu, và quan trọng nhất là một agent mà bạn sẽ không ngồi trước màn hình suốt thời gian nó làm việc, thì đó là lúc bạn muốn dùng durable harness.
Alejandro tóm lại hai điều đã hiểu: định nghĩa của Pi Durable và bài toán nó giải, cùng với chỗ đứng của nó trong kiến trúc Pi. Nó nằm ngay ở tầng Pi Harness. Nó không phải một ứng dụng, nó là một building block. Câu hỏi kế tiếp là dùng building block này để chạy ứng dụng của riêng bạn ra sao, và anh vẽ một cái nhìn tổng quan ở mức cao về ứng dụng đó.
8. Một ứng dụng always-on dựng quanh Pi Durable
Giả sử bạn muốn tạo một trợ lý always-on của riêng mình, và bạn muốn liên lạc với nó qua Slack, qua email. Alejandro lưu ý rằng Pi Durable không chỉ dành cho trợ lý always-on. Nó cũng có thể là một ứng dụng chat thông thường, như một coding agent; điều đó hoàn toàn khả thi. Lát nữa anh sẽ cho xem một script nhỏ minh hoạ harness chạy trong một trợ lý dạng CLI.
Điều xảy ra là bạn sẽ build một kiểu giao diện cho tất cả các đầu vào đó. Lý tưởng là bạn tạo gateway của riêng mình để xử lý mọi đầu vào và chuyển chúng vào ứng dụng. Rồi tới ứng dụng của bạn, mà nhiều khả năng sẽ viết bằng Node.js, vì Pi Durable là một thư viện TypeScript. Bạn import Pi Durable vào ứng dụng này.

Đây là chỗ bạn thấy rõ nó thật sự là một building block: bạn phải tự build ứng dụng xử lý người dùng. Lý tưởng là bạn cũng xử lý conversation ở tầng ứng dụng này. Lý do: dù Pi Durable có API riêng để quản lý conversation của harness, trước hết đó không phải một CRUD API đầy đủ; thứ hai, nó không cho bạn nhiều linh hoạt; và thứ ba, API đó nhiều khả năng sẽ thay đổi, vì Pi Durable còn ở giai đoạn rất sớm trong quá trình phát triển (tính đến ngày video đăng, 19/10/2026).
9. Conversation: thứ gần với session của Pi coding agent
Khi đã có ứng dụng, Pi Durable cho bạn truy cập một loạt công cụ trong API của nó. Bạn có thể tạo nhiều conversation: conversation A, conversation B, conversation C, và dĩ nhiên điều đó rất tốt.
Cách hay để nghĩ về mỗi conversation là coi nó như một session trong Pi coding agent. Alejandro thừa nhận thuật ngữ ở đây có thể hơi phức tạp, hơi gây nhầm lẫn, vì "session" cũng là một từ được Pi Durable dùng cho một thứ khác. Nhưng nếu bạn đến từ Pi coding agent, anh muốn bạn nghĩ về conversation như thứ bạn vẫn gọi là session, theo nghĩa mỗi conversation có system prompt riêng, working directory riêng, và tool cùng skill riêng.

Về cơ bản, nó giống hệt như bạn khởi động Pi coding agent của mình trong một thư mục mới, và thư mục đó có thư mục .pi riêng với đủ mọi thứ. Nhưng ở đây, Pi Durable thực ra không nạp bất cứ thứ gì từ .pi. Nếu bạn có file AGENTS.md, Pi Durable sẽ không dùng nó. Nó chỉ chạy những gì bạn nạp một cách tường minh khi khởi tạo conversation trong code.
Anh hứa sẽ cho xem code ngay sau đây; anh có sẵn một script nhỏ cho thấy cách tạo agent của riêng bạn. Nhưng trước đó, anh muốn trình bày cách nó vận hành về mặt khái niệm, để bạn không phải nhìn một đống code mà không biết chuyện gì đang diễn ra.
Các conversation này dĩ nhiên được nối với các model adapter từ package Pi AI. Và rất quan trọng: để phần "durable" hoạt động được, bạn cần một cơ sở dữ liệu hay một dạng storage nào đó. Anh nói có thể sẽ bàn thêm về storage sau.
10. Storage: SQLite, JSONL hay memory
Storage là một chủ đề sâu hơn một chút. Nhưng có nhiều cách để Pi Durable lưu mọi thứ, lưu trạng thái của bất cứ việc gì nó đang làm trong ứng dụng, và dĩ nhiên cả conversation. Tính đến ngày video đăng (19/10/2026), Pi Durable hỗ trợ một storage backend SQLite. Bạn không phải tự tạo nó: chỉ cần khởi tạo trong code, nó sẽ được tạo và quản lý giúp bạn.
Ngoài ra còn hệ thống storage JSONL, và hệ thống in-memory. Như tên gọi, in-memory sống trong bộ nhớ và bị xoá sau khi bạn đóng ứng dụng, nên nó thực sự chỉ để thử nghiệm. Với ứng dụng production thật, Alejandro khuyên chọn SQLite.

SQLite là thứ anh thích nhất trong các lần thử nghiệm của mình, nhưng anh nhắc rằng JSONL cũng được hỗ trợ. Một điều cần nhớ: storage JSONL của Pi Durable hoàn toàn không giống session file JSONL của Pi coding agent. Trước hết nó gồm nhiều file, không phải chỉ một file cho mỗi conversation, và toàn bộ cách tổ chức đó nhằm làm cho mọi thứ đáng tin cậy, để nó tiếp tục được sau một lần crash hay sự cố tiềm năng.
Đó là những gì diễn ra trong kiến trúc của ứng dụng, và đó là cách bạn import nó. Tiếp theo anh cho xem code trông thế nào, và từng khía cạnh của việc khởi tạo một instance durable harness.
11. Sáu bước khởi tạo một harness
Alejandro tóm lại: giờ ta đã hiểu Pi Durable hoạt động ra sao, nó thực sự là gì, nó nằm ở đâu trong kiến trúc của Pi, và bạn sẽ dựng ứng dụng của mình với thư viện này thế nào. Anh muốn nói về cách dùng nó thực tế và demo trước mặt người xem: một script rất ngắn, chạy một agent tối giản trong terminal.
Nhưng trước khi làm vậy, anh trình bày chính xác các bước script sẽ đi qua, vì nó không thẳng tuột như kiểu chỉ cần tạo một agent rồi chạy. Trước hết bạn phải khởi tạo instance Pi Durable, và việc này diễn ra theo vài bước.

Bước 1 là import hoặc cấu hình các model.
Bước 2 là import hoặc mở registry. Registry chứa mọi tool bạn sẽ dùng, và cả các extension. Trong Pi Durable, và trong Pi nói chung, có sẵn rất nhiều extension, một số được tích hợp sẵn (built-in). Trong ví dụ, anh dùng extension coding agent tools. Nó thêm các tool thông thường bạn đã quen từ Pi; anh nhớ là read, edit, bash và find, nhưng không chắc lắm, và hẹn sẽ xem lại ngay sau.
Bước 3 là thiết lập storage. Nhắc lại, có vài lựa chọn: SQLite, các file JSONL, và memory. Trong ví dụ này anh dùng SQLite để cho thấy nó trông thế nào, nhưng để thử nghiệm thì anh khuyên dùng memory. Anh nói rõ sẽ không dẫn đi hết toàn bộ API. Nếu bạn định dùng nó, hãy dùng cùng một agent: anh không kỳ vọng bạn tự tay code những thứ này.
Bước 4 là mở harness. Bước 5 là tạo hoặc lấy lại một conversation; nhớ rằng conversation về cơ bản giống session trong Pi coding agent thông thường. Và cuối cùng, bước 6 là submit query. Về cơ bản đây chỉ là query harness và nhận câu trả lời.
12. Submit query: await kết quả hay stream sự kiện
Khi bạn submit một thứ gì đó, nó được lưu bền vững vào storage. Nhờ vậy harness, hay agent, có thể nhận lấy việc đó và tiếp tục làm nếu tới lúc nào đó bị gián đoạn.
Một điều quan trọng: khi submit một query, hay về cơ bản bất kỳ thay đổi nào vào harness, bạn sẽ await một phản hồi. Bạn có thể await phản hồi vì như vậy bạn làm được việc khác một cách bất đồng bộ (asynchronously). Hoặc bạn có thể stream các sự kiện. Chọn cách nào tuỳ thuộc vào loại ứng dụng bạn đang build.
Nếu ứng dụng của bạn là kiểu submit job rồi chờ chúng hoàn tất, ví dụ những job mất vài giờ hay thậm chí vài ngày, có lẽ bạn sẽ submit task, chờ nó hoàn tất, rồi lấy phản hồi khi xong. Nhân tiện, khi submit một query bạn nhận lại một submission ID, chính là thứ bạn dùng để xác nhận hay kiểm tra trạng thái task của mình.
Còn nếu thứ bạn build là một ứng dụng chat cần tương tác, bạn cũng có thể stream sự kiện từ harness và nhận chúng ngay khi chúng xảy ra. Như vậy bạn hiển thị được completion ngay khi nó sinh ra, hiển thị các tool call, và bất cứ sự kiện nào khác bạn muốn đưa lên giao diện. Rồi anh chuyển sang code thật: như đã nói, về cơ bản có sáu bước để dựng harness, và tất cả rất thẳng.
13. Demo: agent tối giản chạy model Qwen3.5 0.8B qua llama.cpp
Trước khi đọc code, Alejandro cho xem script thực sự chạy gì. Anh đang chạy một server llama.cpp với một model rất nhỏ, chỉ để minh hoạ cách mọi thứ vận hành: Qwen3.5 0.8B, bản trọng số GGUF BF16 (unsloth/Qwen3.5-0.8B-GGUF). Anh chạy script để sẵn bên cạnh, nối với llama.cpp.
README của repo demo ghi lệnh khởi động server tương ứng như sau (trong video, Alejandro dùng cờ --chat-template-kwargs để tắt thinking; README ghi rằng các bản llama.cpp hiện hành, tính đến 10/2026, coi cờ đó là deprecated và dùng --reasoning off thay thế):
llama-server \ -hf unsloth/Qwen3.5-0.8B-GGUF:BF16 \ --alias qwen3.5-0.8b-bf16 \ --jinja \ --reasoning off \ -c 16384 --parallel 1 -ngl 999 \ --host 127.0.0.1 --port 8080
Trong terminal, anh chạy lệnh dưới đây; npm in ra rằng nó chạy chat.mjs với biến LLAMA_BASE_URL=http://127.0.0.1:8080/v1:
npm run chat:llama
Màn hình in ra cảnh báo của Node rằng SQLite là tính năng thử nghiệm và có thể thay đổi bất cứ lúc nào, rồi số conversation và model llamacpp/qwen3.5-0.8b-bf16, danh sách tool (read, write, edit, bash), đường dẫn file SQLite, dòng "Fresh conversation · scheduling starts when you submit a message", và một cảnh báo màu vàng: tool chạy với quyền của người dùng, đây KHÔNG phải sandbox.
Anh gõ "hello", và như mọi người thấy, phản hồi rất nhanh vì model siêu nhỏ. Agent đáp "Hello! How can I assist you today?".

read {"path":"readme.md"} rồi trả lời "The secret phrase is: Reachy Mini is very cute."Anh đã giấu một câu bí mật trong file README, rồi thử xem agent chạy trên Durable có tìm ra không. Anh hỏi: "read the readme.md file and tell me the secret phrase". Agent dùng được tool: nó gọi read, rồi trả lời câu bí mật là "Reachy Mini is very cute."
Ý ở đây là bạn có một agent hoạt động được. Alejandro nói không dễ cho thấy trực tiếp những gì đang diễn ra phía sau theo thời gian thực, vì nó đang tạo checkpoint, đang tạo storage bền vững bằng SQLite trong trường hợp này, và mọi thứ xảy ra ở hậu trường. Demo này chỉ để cho thấy agent chạy được.
14. Đi qua code của chat.mjs
Thấy agent chạy rồi, anh mở code để xem phía sau có gì. Rất thẳng. Đầu tiên là khởi tạo các model. Ở đây anh dùng một provider cho llama.cpp, nhưng cũng thêm sẵn một nhánh dùng OpenAI key. Đoạn đầu file chat.mjs:
// Fresh-chat example: npm run chat (or npm run chat:llama).
import { randomUUID } from "node:crypto";
import { createModels } from "@earendil-works/pi-ai/models";
import { fauxProvider } from "@earendil-works/pi-ai/providers/faux";
import { openaiProvider } from "@earendil-works/pi-ai/providers/openai";
import { createRegistry, Harness } from "@earendil-works/pi-durable";
import { CodingTools } from "@earendil-works/pi-durable/tools";
import { openNodeSqliteStorage } from "@earendil-works/pi-durable/storage/sqlite/node";
import { llamaProvider } from "./llama-provider.mjs";
import { ctx, createChatSupport } from "./chat-support.mjs";
// 1. Configure models. llama.cpp takes priority over OpenAI settings in .env.
const models = createModels();
let model, fake;
if (process.env.LLAMA_BASE_URL) {
const local = llamaProvider({ baseUrl: process.env.LLAMA_BASE_URL, apiKey: process.env.LLAMA_API_KEY });
models.setProvider(local);
model = { provider: local.id, modelId: local.getModels()[0].id };
} else if (process.env.OPENAI_MODEL) {
if (!process.env.OPENAI_API_KEY) throw new Error("Set OPENAI_API_KEY to use OPENAI_MODEL.");
models.setProvider(openaiProvider());
model = { provider: "openai", modelId: process.env.OPENAI_MODEL };
} else {
fake = fauxProvider(); // Keyless local echo for trying the example.
models.setProvider(fake.provider);
model = { provider: fake.getModel().provider, modelId: fake.getModel().id };
}Provider cho llama.cpp chỉ là một adapter rất đơn giản của Pi. Trong file llama-provider.mjs, bạn tạo một provider bằng createProvider từ API models của Pi AI, điền các thông tin chi tiết (id "llamacpp", baseUrl, API kiểu OpenAI completions, model qwen3.5-0.8b-bf16 với contextWindow 16384 và maxTokens 2048, cost bằng 0), và thế là xong.
Sau đó, như đã nói, là tạo registry: nơi gói lại mọi tool và mọi thứ agent được quyền dùng, chẳng hạn các extension. Anh có thể chỉ khởi tạo registry hoàn toàn rỗng, với cấu hình Pi dựng sẵn thông thường. Nhưng bạn cũng có thể thêm các coding tool có sẵn từ pi-durable/tools: một extension dựng sẵn bạn nạp vào được, đi kèm bốn tool của Pi. Comment trong code ghi bốn tool đó là read, write, edit, bash:
// 2. Configure the registry with the coding tools. const registry = createRegistry(); registry.install(CodingTools); // read, write, edit, bash
Anh hỏi thử agent "what tools do you have available?", và nó trả lời là đọc, ghi và sửa được file. Anh nhận xét: nghe ổn đấy.
Bước kế, sau khi có registry, thực ra trước khi khởi tạo harness thì phải khởi tạo storage. Storage được mở bằng openNodeSqliteStorage, cũng đến từ package của Earendil. Rồi khởi tạo harness, tức class hay instance mang API để tương tác với các conversation: mở harness, truyền vào storage, các model đã khởi tạo, registry, và working directory hiện tại.
// 3. Open SQLite storage.
storage = await openNodeSqliteStorage(demo.databasePath);
// 4. Open the Harness. Its env callback receives the conversation's saved cwd.
harness = await Harness.open(storage, {
models, registry,
env: ({ cwd }) => demo.environmentFor(cwd),
onReport: demo.reportError,
}, ctx);Biến demo chỉ là một helper anh tự viết để gói bớt vài thứ, cho dễ hiểu chuyện gì đang diễn ra; comment trong code ghi rằng helper lo đường dẫn, giao diện terminal và dọn tài nguyên, không phải phần dựng Harness.

chat.mjs: bước 5 tạo conversation với ownership: { kind: "ownerless" } và instructions "You are a helpful, concise assistant."; bước 6 trong vòng lặp đọc terminal: chat.submit trả về submission, rồi chờ submission.wait(ctx) để in câu trả lời.Sau đó, ngay từ harness, bạn tạo một conversation. Phần ownership ở ví dụ này chỉ là "ownerless". Bạn truyền vào model, working directory hiện tại, và instructions, về cơ bản là system prompt. Chỉ vậy thôi. Comment trong code ghi rằng mỗi lần chạy sẽ tạo một conversation mới, không resume hay phát lại lịch sử khi khởi động.
Sau đó bạn query thẳng conversation đó. Để tạo một submission, bạn lấy chính instance conversation vừa tạo và gửi submission bằng method submit. Method submit trả về submission, và bạn chỉ việc chờ nó hoàn tất rồi hiển thị câu trả lời. Đó chính là thứ đã chạy bên cạnh, với coding agent vừa demo. Đoạn này trên màn hình (dòng submit bị che một phần ở mép phải):
// 5. Every launch creates a new conversation. No startup resume or history replay.
const chat = await harness.createConversation({
ownership: { kind: "ownerless" },
agent: { model, cwd: process.cwd(), instructions: "You are a helpful, concise assistant." },
}, ctx);Alejandro nhấn mạnh rằng đây chỉ là một demo rất nhanh về API của durable harness. Nó không phải một ứng dụng hoàn chỉnh. Nó là kiến trúc harness, hay primitive durable harness, để bạn dùng trong ứng dụng của mình. Và nó thực sự rất thẳng: nó vận hành gần như một thứ thay thế cho Pi SDK, nếu thứ bạn đang build là một durable agent, chẳng hạn một trợ lý always-on. Code của ví dụ có trong repo đi kèm video (alejandro-ao/pi-durable-demo).
15. chat:resume: dừng giữa chừng rồi chạy tiếp từ SQLite
Anh còn làm thêm một ví dụ thứ hai, phức tạp hơn một chút, tên là chat resume. Nó làm gần như cùng việc, nhưng tiếp tục conversation sau khi bạn khởi động lại, từ đúng điểm nó đã dừng, để bạn thấy tận mắt phần "durable". Chạy nó bằng:
npm run chat:resume
Lệnh này chạy script chat-resume.mjs. Như anh nói, nó làm những việc giống ví dụ trước: tạo phần chat support, tạo storage, tạo registry, thêm coding tools, khởi tạo harness. Nhưng sau đó nó kiểm tra trạng thái của storage, tức trạng thái bền vững của harness, rồi tiếp tục từ điểm đó. Trên màn hình, bước 5 của file này ghi rằng nó mở lại conversation đã lưu, hoặc tạo một conversation ở lần chạy đầu: harness.inspect(ctx) tìm các submission chưa xong, chọn submission gần nhất, lấy lại conversation, in "Recovery enabled · reopening the saved conversation", gọi harness.resume(), rồi nếu có submission đã lưu thì nối lại với nó và chờ câu trả lời.
Khi anh chạy npm run chat:resume, hoá ra đang có sẵn một task chưa hoàn tất từ trước. Anh hỏi: "read the documentation of this project and tell me what it does". Agent suy nghĩ một chút, có lẽ sẽ gọi vài tool. Và anh dừng nó lại: nó dừng ngay sau khi gọi tool đọc package.json.

read {"path":"package.json"} thì process bị dừng; Alejandro gõ lại npm run chat:resume để khởi động lại. Phía trên còn phần trả lời của lần chạy trước (execution path, safety and storage notes, tests).Rồi anh xem chuyện gì xảy ra nếu chạy lại và resume với đúng yêu cầu đó. Nó đọc từ storage, ở đây là cơ sở dữ liệu SQLite như đã cho xem, và tiếp tục sau tool call read. Và đúng vậy: sau tool call, nó gửi cho anh câu trả lời ngắn, rằng đây là một app demo kỹ thuật chạy cục bộ, vân vân. Trên màn hình, câu trả lời liệt kê dự án làm gì: chạy một dashboard tự chứa (Node và SQLite, không cần build frontend) trên localhost; tạo một "job" demo nhiều bước, lưu checkpoint durable trong SQLite và thực hiện một hiệu ứng bên ngoài (ghi một file) giữa intent và outcome; cho điều khiển việc chạy từng bước bằng breakpoint, chạy liên tục, hoặc ép crash sau khi ghi file rồi khởi động lại để thấy hồi phục từ checkpoint; và giải thích các khái niệm như checkpoint với outcome, commit DB nguyên tử với hiệu ứng bên ngoài không nguyên tử, idempotency khi thử lại. Phần "Intended use" ghi rằng đây là công cụ học cục bộ, an toàn, không phải một service mở ra internet.
Alejandro chốt lại: đó về cơ bản là Pi Durable. Bạn có hai script để hiểu chuyện gì thực sự đang diễn ra, và tất cả đều có trong phần mô tả: script chat resume chạy bằng npm, và script thông thường, về cơ bản chỉ là một màn trình diễn mức cao của Harness API. README của repo ghi rằng các package Pi được ghim ở bản 1.2.0 cho khớp với video, và đây là ví dụ để học, không phải agent production.
Anh mời mọi người đặt câu hỏi nếu có, hy vọng video đã phủ gần như mọi thứ liên quan tới Pi Durable, và người xem đã hiểu rõ hơn nó hoạt động thế nào và hữu ích cho việc gì. Anh cảm ơn mọi người đã xem, và mời like, subscribe để gặp lại ở video sau.
Nguồn và liên kết 11 nguồn
- Tên gốc: Pi Durable EXPLAINED: Build Always-On Agents with Local Models
- Sự kiện: YouTube
- Video gốc: https://www.youtube.com/watch?v=ti3vVYwzW4A youtube.com
- Kênh YouTube Hugging Face (Alejandro AO): youtube.com/channel/UCHlNU7kIZhRgSbhHvFoy72w youtube.com
- Repo đi kèm video, hai ví dụ
chat.mjsvàchat-resume.mjs, lệnh llama-server và câu bí mật trong README: github.com/alejandro-ao/pi-durable-demo github.com - Bài giới thiệu Pi Durable của Earendil (01/10/2026: harness, conversation, task, storage memory/SQLite/JSONL): earendil.com/posts/pi-durable earendil.com
- Mã nguồn Pi: github.com/earendil-works/pi github.com
- Trang chủ Pi: pi.dev pi.dev
- llama.cpp: github.com/ggml-org/llama.cpp github.com
- Model Qwen3.5-0.8B: huggingface.co/Qwen/Qwen3.5-0.8B huggingface.co
- Trọng số GGUF dùng trong demo (BF16): huggingface.co/unsloth/Qwen3.5-0.8B-GGUF huggingface.co