jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Handoff Skill — bàn giao context & tài liệu sống cho agent

Viết một skill handoff giữ tài liệu sống trong notes/ (progress, handoff log, architecture) và update mỗi lần đổi code, để agent mới resume mà không explore lại. Build từng bước + cách nâng lên global skill.

This is the next part of the Cursor AI Agent series, after Cursor Skills for beginners and Cursor Sub-agents. {Đây là phần tiếp theo của series Cursor AI Agent, sau Cursor Skills cho người mớiCursor Sub-agents.}

In the sub-agent post there was one easily-missed line: save important output to a file so it survives when the parent context gets long. {Ở bài sub-agent có một dòng dễ bị bỏ qua: lưu output quan trọng ra file để không mất khi context parent dài.} This post turns that idea into a concrete skill — handoff — that keeps a set of living docs so every working session can hand off to the next. {Bài này biến ý đó thành một skill cụ thể — handoff — giữ một bộ tài liệu sống để mỗi phiên làm việc bàn giao được cho phiên sau.}


1. The problem: context dies between sessions

{Vấn đề: context chết giữa các phiên}

Each conversation with an agent is its own context window. {Mỗi conversation với agent là một context window riêng.} When you close the chat or it resets because the window filled up, everything it learned — the structure, what each file does, what was decided and why — disappears. {Khi bạn đóng chat hoặc nó reset vì context đầy, mọi thứ nó học được — cấu trúc, file nào làm gì, đã quyết định gì và vì sao — biến mất.}

Session 1:  explore 30 files → understand → 60% done → out of context

              ▼  (close chat / reset)
Session 2:  "Wait, what is this project?" → explore 30 files again → ...

You pay tokens twice for the same “understand the codebase” work, and worse: session 2 may decide differently because it doesn’t know why session 1 chose what it chose. {Bạn trả token 2 lần cho cùng việc “hiểu codebase”, và tệ hơn: phiên 2 có thể quyết định khác vì không biết lý do của quyết định cũ.}

The fix is not a bigger context window. It is writing state out of the context — into files — so the next session reads it back. That is handoff. {Giải pháp không phải context to hơn, mà là ghi state ra ngoài context — vào file — để phiên sau đọc lại. Đó là handoff.}


2. From “save a file” to a living doc system

{Từ “lưu một file” tới một hệ tài liệu sống}

A single notes.md rots fast. The trick is to split docs by how often they change and to update them on every code change, not just at the end. {Một file notes.md đơn lẻ mục rất nhanh. Mẹo là tách tài liệu theo tần suất thay đổi và update mỗi lần đổi code, không phải chỉ lúc cuối.}

notes/
├── progress.md            # status table — what's done / doing / next
├── handoff.md             # chronological log — date+time, files, what/next
├── architectures.md       # the map — structure + links to split docs
├── getting-started.md     # setup / run / build           (optional)
├── frontend-architecture.md  # component & layout tree     (optional)
├── content-architecture.md   # data layer / schemas        (optional)
└── {feature-name}.md      # one file per LARGE feature

working.md (at the repo root) stays as a lightweight “current vs previous request” scratch. Everything durable lives in notes/. {working.md (ở gốc repo) là scratch nhẹ “request hiện tại vs trước đó”. Mọi thứ bền vững nằm trong notes/.}


3. The two docs that do the heavy lifting

{Hai file gánh phần nặng nhất}

progress.md and handoff.md answer two different questions. {progress.mdhandoff.md trả lời hai câu khác nhau.}

FileQuestion it answersShape
progress.md”Where do things stand now?”A status table
handoff.md”What happened, when, and why?”A chronological log

progress.md is the current state — overwrite freely, keep it short. {progress.mdtrạng thái hiện tại — ghi đè thoải mái, giữ ngắn.} handoff.md is the history — append-only session entries, each with an exact date and time, the files changed, what was done, and what’s next. {handoff.mdlịch sử — append từng phiên, mỗi entry có date+time chính xác, file đã đổi, đã làm gì, làm tiếp gì.}

Keeping history out of progress.md is what stops it from bloating — the trap that made the old single-file approach useless. {Tách lịch sử khỏi progress.md chính là cái giữ nó không phình — đúng cái bẫy khiến cách 1-file cũ thành vô dụng.}


4. Why notes/ and not .cursor/

{Vì sao là notes/ chứ không phải .cursor/}

This is deliberate: notes/ is project documentation, not tool config. {Đây là quyết định có chủ đích: notes/tài liệu của project, không phải config của tool.}

  • Humans read it too — a new dev opens notes/architectures.md and gets the system without an agent. {Con người cũng đọc — dev mới mở notes/architectures.md là hiểu hệ thống mà không cần agent.}
  • It is tool-agnostic — switch away from Cursor and notes/ still holds value; .cursor/ is tied to one tool. {Nó độc lập với tool — đổi khỏi Cursor thì notes/ vẫn còn giá trị; .cursor/ thì gắn chặt một tool.}
  • Commit policy is yours — commit notes/ as shared team memory, or gitignore it as scratch. Either works. {Quyền commit là của bạn — commit notes/ làm “bộ nhớ chung”, hoặc gitignore nếu coi là scratch. Đều được.}

Convention: every project uses ./notes/, so the skill only ever needs to know one path. {Quy ước: mọi project dùng ./notes/, nên skill chỉ cần biết một đường dẫn duy nhất.}


5. The key rule: update on EVERY change

{Quy tắc cốt lõi: update MỖI lần đổi code}

The skill does not wait for “save progress”. It triggers after any meaningful edit: {Skill không đợi tới lúc “save progress”. Nó kích hoạt sau mỗi edit đáng kể:}

  • Implementing or modifying a screen / route / component {Làm hoặc sửa một screen / route / component}
  • Adding or changing an API endpoint or data model {Thêm hoặc đổi API endpoint hoặc data model}
  • Changing dependencies, config, or any architecture {Đổi dependency, config, hoặc bất kỳ kiến trúc nào}

Why so aggressive? Because docs written “later” are never written. Tying the update to the edit keeps them true. {Vì sao gắt vậy? Vì tài liệu để “viết sau” thì không bao giờ được viết. Gắn update vào edit giữ chúng luôn đúng.}


6. Build the skill step by step

{Build skill từng bước}

Following the four phases: Discovery → Design → Implementation → Verification. {Theo 4 phase: Discovery → Design → Implementation → Verification.}

Phase 1 — Discovery

Answer five questions. {Trả lời 5 câu.}

  1. What does it solve? Hand off state between sessions and keep docs current. {Giải quyết gì? Bàn giao state giữa các phiên và giữ tài liệu luôn mới.}
  2. Personal or project? Project first (.cursor/skills/handoff/); promote to global later. {Personal hay project? Project trước; nâng lên global sau.}
  3. When should it load? On resume, and after any code change. {Khi nào load? Lúc resume, và sau mỗi lần đổi code.}
  4. Special output? Yes — the notes/ doc set + templates. {Output đặc biệt? Có — bộ doc notes/ + template.}
  5. Existing pattern? Workflow Pattern (read → work → write loop). {Pattern sẵn? Workflow Pattern (vòng read → work → write).}

Phase 2 — Design

The description decides whether the skill ever triggers. Third person, WHAT + WHEN, stuffed with trigger terms: {description quyết định skill có được trigger không. Ngôi thứ ba, WHAT + WHEN, nhồi trigger terms:}

description: Maintain living project docs in notes/ and hand off between sessions. Update docs on EVERY code change (new screen, feature, flow, bug fix, schema, architecture) and read them first on resume. Use when implementing, modifying, fixing, refactoring, resuming, saving progress, or updating notes.

Phase 3 — Implementation

Directory layout, references one level deep: {Cấu trúc thư mục, references chỉ 1 cấp sâu:}

.cursor/skills/handoff/
├── SKILL.md
├── progress-template.md
├── handoff-template.md
└── architecture-template.md

The core of SKILL.md — the trigger list, the doc set, and the per-change steps: {Phần lõi của SKILL.md — danh sách trigger, bộ doc, và các bước mỗi lần đổi:}

---
name: handoff
description: Maintain living project docs in notes/ and hand off between sessions. Update docs on EVERY code change ... Use when implementing, modifying, fixing, resuming, saving progress, or updating notes.
---

# Handoff

## When to trigger
Update docs after: implementing/modifying a screen, changing an endpoint or
schema, adding components, changing auth, deps, or any architecture.
Read docs first when resuming or starting a non-trivial task.

## Steps on every change
1. Identify what changed (files created/modified/deleted; large feature?).
2. Update `notes/progress.md` (status table: ✅ / 🟡 / ⬜).
3. Update `notes/handoff.md` (session entry: date+time, files, what, next).
4. Update architecture docs only if structure changed.
5. Update `working.md` at repo root (current vs previous request).

## If notes/ is missing
Bootstrap from templates: progress-template.md, handoff-template.md,
architecture-template.md.

The handoff.md session-log template is the new piece compared to v1: {Template session-log handoff.md là phần mới so với v1:}

## Session N — May 29, 2026, 10:15

### What was done
1. [First thing]
2. [Second thing]

### Files changed
- `path/to/file` — what changed

### What's next
- [ ] [Next task]

Phase 4 — Verification

  • SKILL.md under 500 lines. {SKILL.md dưới 500 dòng.}
  • Description is specific, third person, full of trigger terms. {Description cụ thể, ngôi thứ ba, nhiều trigger terms.}
  • References one level deep (SKILL.md → templates, no deeper). {References 1 cấp sâu (SKILL.md → template, không sâu hơn).}
  • Test it: open a new chat, say “resume where we left off”, check it reads notes/ first. {Test thật: mở chat mới, gõ “resume where we left off”, xem nó có đọc notes/ trước không.}

7. Large features get their own file

{Feature lớn được file riêng}

Don’t bloat a main doc with a 200-line feature write-up. For a major feature (new module, new page group, major flow), create notes/{feature-name}.md and add a reference link from the main doc. {Đừng nhồi 200 dòng mô tả feature vào doc chính. Với feature lớn (module mới, nhóm page mới, flow lớn), tạo notes/{feature-name}.md rồi thêm link tham chiếu từ doc chính.}

Rule of thumb: split it out when it would add more than ~50 lines to an existing doc, or when it’s a self-contained area (an admin panel, a payment integration, an OAuth setup). {Quy tắc: tách ra khi nó thêm hơn ~50 dòng vào doc có sẵn, hoặc khi nó là một mảng độc lập (admin panel, payment, OAuth setup).}


8. Using it in practice

{Dùng trong thực tế}

Resume flow

Open a new chat in a repo that already has notes/ and say: {Mở chat mới trong repo đã có notes/ và gõ:}

Continue working on this project.

The agent reads notes/progress.md + handoff.md + architectures.md first, then says what’s left and picks up — no re-exploring 30 files. {Agent đọc notes/progress.md + handoff.md + architectures.md trước, rồi nói còn gì và làm tiếp — không explore lại 30 file.}

Update flow

After a chunk of work, or when context feels full: {Sau một mảng việc, hoặc khi thấy context sắp đầy:}

Update the notes and hand off.

It appends a handoff.md entry (with timestamp + files changed), refreshes the progress.md table, and touches any architecture doc whose area changed. {Nó thêm một entry handoff.md (kèm timestamp + file đã đổi), làm mới bảng progress.md, và đụng vào doc architecture nào có vùng thay đổi.}

Live demo on this blog

{Demo sống trên blog này}

This repo already runs the convention: {Repo này đã chạy đúng quy ước:}

notes/
├── progress.md             # status table of blog tasks
├── handoff.md              # session log (this post was written across sessions)
├── architectures.md        # blog map → links to the split docs below
├── getting-started.md
├── frontend-architecture.md
└── content-architecture.md

9. Promote to a global skill

{Nâng lên global skill}

Once it works in one project, reuse it everywhere by copying it to the personal scope: {Khi đã chạy ổn ở một project, dùng lại ở mọi nơi bằng cách copy sang scope personal:}

cp -r .cursor/skills/handoff ~/.cursor/skills/handoff
ScopePathWho uses it
Project.cursor/skills/handoff/Anyone who opens this repo (via git)
Personal~/.cursor/skills/handoff/Every project on your machine

Nothing else changes — the skill always writes to ./notes/ relative to the open project, so the same convention applies everywhere. {Không cần sửa gì — skill luôn ghi vào ./notes/ tương đối theo project đang mở, nên cùng quy ước áp dụng ở mọi nơi.}

Never put it in ~/.cursor/skills-cursor/ — that folder is for Cursor’s built-in skills and may be overwritten on update. {Đừng để trong ~/.cursor/skills-cursor/ — folder đó dành cho skill built-in của Cursor, có thể bị ghi đè khi update.}


10. Anti-patterns

{Anti-patterns}

Putting history in progress.md. It bloats. History belongs in handoff.md; progress.md only shows the current state. {Nhét lịch sử vào progress.md. Nó phình. Lịch sử thuộc về handoff.md; progress.md chỉ hiện trạng thái hiện tại.}

A play-by-play of every edit. Record decisions and why, not “changed line 42”. The diff already tells what changed. {Kể từng dòng edit. Ghi quyết định và vì sao, không phải “sửa dòng 42”. Diff đã kể cái gì đổi rồi.}

architectures.md as a changelog. It describes current structure; git is the changelog. {architectures.md thành changelog. Nó mô tả cấu trúc hiện tại; git mới là changelog.}

Writing but never reading. The loop starts with read. If the agent jumps into exploring, tell it to read notes/ first. {Ghi mà không đọc. Vòng lặp bắt đầu bằng read. Nếu agent nhảy vào explore, nhắc nó đọc notes/ trước.}

References nested too deep. SKILL.mda.mdb.md: the agent may not read that far. Keep it one level. {References lồng quá sâu. SKILL.mda.mdb.md: agent có thể đọc không tới. Giữ 1 cấp.}


Summary

{Tổng kết}

The handoff skill turns the agent’s memory from ephemeral (dies with the context window) into persistent (lives in notes/): {Handoff skill biến “bộ nhớ” của agent từ ephemeral (chết theo context window) thành persistent (sống trong notes/):}

  1. Split by change rate: progress.md (now), handoff.md (history), architectures.md (structure). {Tách theo tần suất đổi: progress.md (hiện tại), handoff.md (lịch sử), architectures.md (cấu trúc).}
  2. Update on every change, not “later”. {Update mỗi lần đổi code, không để “lúc sau”.}
  3. Large features get their own file, linked from the main doc. {Feature lớn được file riêng, link từ doc chính.}
  4. notes/ is documentation, usable by humans and any tool. {notes/ là tài liệu, dùng được cho con người và mọi tool.}
  5. Project first, global later — review via git, then cp to ~/.cursor/skills/. {Project trước, global sau — review qua git, rồi cp sang ~/.cursor/skills/.}

Start by adding notes/progress.md and notes/handoff.md to the project you’re most deep in — the next agent session will “remember” instead of asking you from scratch. {Bắt đầu bằng cách thêm notes/progress.mdnotes/handoff.md cho project bạn đang làm dở nhất — phiên agent kế tiếp sẽ “nhớ” thay vì hỏi lại bạn từ đầu.}