Vibe coding cho cảm giác rất nhanh: mô tả yêu cầu, để agent tạo file, viết API, sửa bug hoặc refactor. Với project nhỏ, cách này thường đủ tốt. Khi codebase lớn dần, câu hỏi không còn là AI có viết được code hay không. Tôi quan tâm nhiều hơn đến việc nó đang đọc gì, sửa gì và dựa vào đâu để kết luận task đã xong:
- AI có đang đọc đúng phần code cần thiết không?
- Nó có quét cả repository và đốt context không cần thiết không?
- Nó có hiểu dependency và những file bị ảnh hưởng không?
- Một session mới có phải đọc lại toàn bộ project từ đầu không?
- Khi sửa bug, nó có tìm root cause hay chỉ patch triệu chứng?
- Sau khi sửa xong, nó có thực sự chạy test hay chỉ nhìn code rồi nói “done”?
- Nếu test command chưa được cấu hình, AI có vô tình coi task là hoàn thành không?
My Vibe Kit ra đời từ đúng những vấn đề đó.
Repository: github.com/cuongtobi/my-vibe-kit
Hiện tôi dùng kit như một workflow chung cho Codex, Claude Code và Google Antigravity. Phần runtime được tách khỏi từng agent, nên logic kiểm tra project không phụ thuộc vào một công cụ cụ thể.
My Vibe Kit là gì?
Tôi cố tình giữ My Vibe Kit nhỏ. Phần agent nhìn thấy chỉ nên đủ để biết phải làm gì; những việc có thể xác định bằng code thì đẩy xuống runtime. Toàn bộ workflow công khai chỉ có 4 skill:
vibe
plan
build
verify
Trong đó:
vibeđiều phối toàn bộ task.planthu thập context, dependency, impact và lập kế hoạch.buildthực hiện thay đổi trong đúng scope.verifykiểm chứng kết quả bằng runtime evidence.
Luồng cơ bản:
vibe
↓
plan
↓
build
↓
verify
Nếu bung chi tiết hơn:
User request
↓
VIBE
↓
PLAN
├── project context
├── dependency graph
├── relevant context
├── impact analysis
├── architecture policy
└── acceptance criteria
↓
BUILD
├── minimal code change
├── focused tests
└── preserve existing user changes
↓
VERIFY
├── dependency diff
├── lint / typecheck / test / build
├── acceptance evidence
└── final diff review
↓
PASS_VERIFIED
Ở bước cuối, code trông hợp lý vẫn chưa đủ. Task chỉ được coi là đã kiểm chứng khi các verification command thực sự chạy và pass. Vì vậy, PASS_VERIFIED là trạng thái có bằng chứng đi kèm, không phải kết luận theo cảm giác của agent.
Nếu project chưa có command kiểm chứng đáng tin cậy, runtime trả về:
NEEDS_VERIFICATION_CONFIG
Nếu chưa có cách kiểm chứng đáng tin cậy, kit dừng ở trạng thái này thay vì tự coi task là xong.
Vì sao tôi không muốn agent đọc toàn bộ project mỗi session?
Với project sống lâu, context nhanh chóng trở thành vấn đề thực tế. Cách đơn giản nhất là mỗi session mới:
scan toàn repository
→ đọc nhiều file
→ đọc task cũ
→ đọc dependency
→ bắt đầu làm
Cách này hoạt động với project nhỏ, nhưng càng lớn càng tốn token và càng dễ đưa những thông tin không liên quan vào context. My Vibe Kit không làm vậy. Nó chia thông tin thành bốn lớp:
durable project truth
persistent local state
current-task runtime
cold task history
Durable project truth
Lớp này chứa những gì tôi coi là nguồn sự thật của project:
AGENTS.md
.vibe/config.json
source code
tests
package manifests
architecture docs
Nếu lịch sử chat mâu thuẫn với source hiện tại, source luôn được ưu tiên.
Persistent state
Context và dependency đã tính toán được cache tại:
.vibe/state/
├── index-state.json
├── file-index.json
├── last-context.json
├── last-dependency.json
├── last-framework.json
├── last-adapter.json
└── last-architecture.json
Phần này chỉ là cache để tiết kiệm thời gian và token; nó không được dùng làm bằng chứng kiểm chứng. Runtime kiểm tra Git state, file hash, config hash và checksum trước khi tái sử dụng cache.
Có ba trạng thái chính:
CACHE_HIT
INCREMENTAL_REFRESH
FULL_REBUILD
CACHE_HIT
Repository không thay đổi. Runtime tái sử dụng context/dependency cũ.
INCREMENTAL_REFRESH
Git phát hiện một số file thay đổi. Runtime chỉ refresh phần bị ảnh hưởng thay vì quét lại toàn project.
FULL_REBUILD
Dùng khi:
- chạy lần đầu,
- cache bị hỏng,
- scanner version thay đổi,
- Git delta không đáng tin cậy,
- hoặc user yêu cầu rebuild.
Nhờ vậy, session mới không phải đọc lại cả repository chỉ để khôi phục bối cảnh cơ bản.
Bounded context: chỉ đưa phần cần thiết cho AI
Dependency graph có thể rất lớn, nhưng model không cần nhìn toàn bộ graph. My Vibe Kit tạo:
.vibe/runtime/relevant-context.json
với context được giới hạn. Mặc định first-pass:
20 source files
10 test files
8 related modules
dependency depth = 2
Agent đọc neighborhood này trước. Nếu một dependency, consumer, failing test hoặc contract cho thấy cần mở rộng scope thì mới đọc thêm. Cách đọc context vì thế gần với:
find the relevant neighborhood
↓
reason locally
↓
expand only with evidence
thay vì:
load everything
↓
hope the important part is somewhere inside
Adapter: cùng một workflow nhưng hiểu từng stack
Bốn skill cốt lõi không được viết riêng cho từng framework. Thay vào đó runtime detect:
language
+
framework
↓
active-adapter.json
Ví dụ:
Python + FastAPI
TypeScript + React + Vite
TypeScript + Next.js
PHP + Laravel
PHP + WordPress
Ruby + Rails
Java + Spring
Go + Gin
Rust + Actix Web
Adapter cung cấp cho workflow những thông tin như:
- manifest,
- dependency scanner,
- route,
- controller,
- component,
- model,
- framework convention,
- verification command phù hợp.
Ví dụ với FastAPI:
language adapter: python
framework adapter: fastapi
Python dùng AST để xây local import graph. FastAPI adapter bổ sung context cho:
routes
APIRouter
Depends
Pydantic schemas
và architecture guidance như:
- tách transport schema khỏi business logic khi cần,
- theo dõi dependency được inject qua
Depends, - giữ route handler mỏng nếu workflow bắt đầu phức tạp.
Architecture policy: không ép Clean Architecture vào mọi project
Coding agent cũng rất dễ over-engineer nếu prompt không đặt ranh giới rõ. Một feature nhỏ đôi khi bị biến thành:
interface
repository
service
factory
adapter
port
DTO
mapper
use case
trong khi project thực tế chỉ cần vài function rõ ràng. My Vibe Kit mặc định dùng:
feature-first
+
modular layered
+
framework-native
+
Clean Code
Profile mặc định:
standard
Flow tư duy cơ bản:
presentation / route / controller
↓
application / service
↓
domain / business rules
↓
data / infrastructure boundary
Nhưng không bắt buộc phải tạo mọi layer. Rule quan trọng là:
Chỉ thêm abstraction khi có boundary, variation, reuse hoặc testing need thực sự.
Khi project lớn hơn hoặc được cấu hình strict, kit có thể chuyển sang dependency rule kiểu Clean/Hexagonal. Framework convention vẫn được ưu tiên. FastAPI nên vẫn trông giống FastAPI.
Rails nên vẫn giống Rails. Laravel vẫn nên dùng convention của Laravel.
Ví dụ: dùng My Vibe Kit với một project FastAPI nhỏ
Giả sử chúng ta có project:
vibe-sample-fastapi/
├── app/
│ ├── __init__.py
│ └── main.py
├── tests/
│ └── test_health.py
└── pyproject.toml
1. Tạo FastAPI project
pyproject.toml:
[project]
name = "vibe-sample-fastapi"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"fastapi",
"uvicorn"
]
[project.optional-dependencies]
dev = [
"pytest",
"httpx",
"ruff"
]
app/main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok"}
tests/test_health.py:
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
def test_health() -> None:
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "ok"}
Cài dependency theo cách bạn đang dùng cho project, sau đó chạy:
python -m pytest -q
Project lúc này chỉ có một endpoint:
GET /health
2. Cài My Vibe Kit vào project
Clone kit:
git clone https://github.com/cuongtobi/my-vibe-kit.git
cd my-vibe-kit
Cài vào FastAPI project:
python install.py \
--target /path/to/vibe-sample-fastapi \
--agents codex claude antigravity
Trên PowerShell:
python .\install.py `
--target C:\code\vibe-sample-fastapi `
--agents codex claude antigravity
Installer sẽ materialize workflow vào project. Sau đó project có thêm các phần như:
vibe-sample-fastapi/
├── .agents/
├── .claude/
├── .vibe/
│ ├── adapters/
│ ├── config.json
│ ├── state/
│ ├── runtime/
│ ├── tasks/
│ └── tools/
├── AGENTS.md
├── CLAUDE.md
├── app/
├── tests/
└── pyproject.toml
Installer detect được:
Python
+
FastAPI
và có thể discover các verification tool đã khai báo như:
ruff
pytest
3. Giao một task cho agent
Giả sử tôi muốn thêm Todo API. Thay vì viết prompt rất dài mô tả từng bước, tôi chỉ cần yêu cầu:
Use vibe to add POST /tasks.
Request body:
- title: string
Response:
- id: integer
- title: string
- done: false
Keep storage in memory for now.
Add tests.
Từ đây vibe điều phối toàn bộ workflow.
4. PLAN — trước khi sửa code
Đầu tiên task được phân loại:
mode = feature
Runtime tạo task record mới. Về logic, agent sẽ chạy các bước tương đương:
python .vibe/tools/vibe.py task start \
--mode feature \
--request "add POST /tasks"
Sau đó refresh project facts:
python .vibe/tools/vibe.py context --summary
python .vibe/tools/vibe.py deps --summary
python .vibe/tools/vibe.py relevant
Runtime lúc này biết:
primary language: python
framework: fastapi
Dependency scanner Python dùng AST để nhìn local import graph. FastAPI framework context tìm route và router liên quan. Architecture policy cũng được materialize. Các artifact có thể xuất hiện tại:
.vibe/runtime/
├── current-task.json
├── project-map.json
├── framework-map.json
├── active-adapter.json
├── architecture-policy.json
├── dependency-map.json
└── relevant-context.json
Agent không cần đọc toàn repository. Với project nhỏ này context có thể rất ít, ví dụ:
app/main.py
tests/test_health.py
pyproject.toml
Snapshot trước thay đổi
Trước khi implementation bắt đầu:
python .vibe/tools/vibe.py snapshot before
Dependency baseline ban đầu được giữ lại. Nếu workflow phải re-plan hoặc session bị ngắt, baseline này không được âm thầm thay thế bằng state mới. Lấy snapshot “before” sau khi code đã bị sửa sẽ khiến dependency diff mất ý nghĩa.
5. Impact analysis
Khi target đã rõ, kit có thể chạy:
python .vibe/tools/vibe.py impact app/main.py
Mục tiêu không phải chỉ hỏi:
File nào tôi định sửa?
Mà còn hỏi:
File nào phụ thuộc vào nó, test nào liên quan, route nào bị ảnh hưởng?
Ví dụ:
target
app/main.py
affected tests
tests/test_health.py
framework
fastapi
routes
GET /health
Nếu project lớn hơn và route import service khác, reverse dependency graph có thể chỉ ra thêm consumers cần kiểm tra.
6. Plan có acceptance criteria cụ thể
Thay vì plan kiểu:
1. sửa API
2. thêm test
3. chạy test
kit khuyến khích acceptance criteria có thể kiểm chứng. Ví dụ:
AC1
POST /tasks với title hợp lệ trả HTTP 200/201.
AC2
Response có:
id
title
done=false
AC3
Task mới được giữ trong in-memory store.
AC4
GET /health cũ vẫn hoạt động.
AC5
pytest và ruff pass.
Mỗi criterion phải gắn với evidence:
AC1 → API test
AC2 → response assertion
AC3 → behavior test
AC4 → existing regression test
AC5 → verification commands
Mục đích là tránh trường hợp:
tests pass
nhưng phần user thực sự yêu cầu lại chưa được test.
7. BUILD — thay đổi nhỏ nhất có thể
Sau plan, build triển khai trong đúng scope. Với demo nhỏ, agent có thể tạo code tương tự:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class CreateTask(BaseModel):
title: str
class Task(BaseModel):
id: int
title: str
done: bool = False
tasks: list[Task] = []
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok"}
@app.post("/tasks")
def create_task(payload: CreateTask) -> Task:
task = Task(
id=len(tasks) + 1,
title=payload.title,
)
tasks.append(task)
return task
và test:
def test_create_task() -> None:
response = client.post(
"/tasks",
json={"title": "Learn My Vibe Kit"},
)
assert response.status_code == 200
assert response.json() == {
"id": 1,
"title": "Learn My Vibe Kit",
"done": False,
}
Ở ví dụ này, kit không ép project phải có repository interface, service layer hay database adapter. In-memory storage là yêu cầu hiện tại. Project còn nhỏ. Không có lý do để thêm abstraction chỉ để trông “enterprise”.
Nếu sau này task đổi thành PostgreSQL, lúc đó boundary dữ liệu mới trở nên có ý nghĩa.
8. VERIFY — code viết xong chưa có nghĩa là task đã xong
Sau implementation, verify refresh lại state:
python .vibe/tools/vibe.py context --summary
python .vibe/tools/vibe.py deps --summary
Nếu task có baseline hợp lệ:
python .vibe/tools/vibe.py snapshot after
Runtime có thể tạo dependency diff:
added edges
removed edges
new cycles
unexpected consumers
Sau đó:
python .vibe/tools/vibe.py verify --summary
Với FastAPI demo, verification có thể chạy:
python -m ruff check .
python -m pytest -q
Nếu tất cả pass, source fingerprint ổn định và không xuất hiện dependency cycle bị cấm:
PASS_VERIFIED
Nếu command fail:
FAIL_VERIFICATION
Nếu chưa có command nào được cấu hình:
NEEDS_VERIFICATION_CONFIG
Đây là nguyên tắc tôi muốn giữ xuyên suốt kit:
Không có test evidence thì không gọi đó là verified.
Nếu verification command tự sửa source thì sao?
Một edge case khá nguy hiểm là formatter hoặc generator chạy trong verification nhưng lại thay đổi source code. Ví dụ:
verify command
↓
formatter thay file
↓
test cũ đã chạy trên state trước
Nếu vẫn báo pass thì evidence đã stale. My Vibe Kit bind verification với source fingerprint. Nếu input thay đổi trong quá trình verify:
rerun_required = true
Các command liên quan phải chạy lại trên final tree.
Workflow sửa bug khác gì feature?
Với bug, vibe dùng flow chặt hơn:
REPRODUCE
↓
ROOT CAUSE
↓
FAILING REGRESSION TEST
↓
MINIMAL FIX
↓
PASSING REGRESSION TEST
↓
AFFECTED TESTS
↓
VERIFY
Ý tưởng là tránh kiểu:
thấy exception
→ thêm if
→ exception biến mất
→ done
Agent phải cố xác định root cause từ evidence và giữ regression test nếu có thể.
Current task và task history
Một điều tôi không muốn là mỗi session mới lại đọc hàng chục task cũ. Do đó:
.vibe/tasks/
được coi là cold history. Agent chỉ tập trung vào current task:
.vibe/runtime/current-task.json
Nếu user tiếp tục cùng mục tiêu ở session sau, workflow tái sử dụng task hiện tại và baseline gốc. Không tạo task mới chỉ vì:
- mở session mới,
- verification fail,
- prompt được diễn đạt lại,
- phải re-plan.
Nhờ vậy, lịch sử task không bị phình ra chỉ vì đổi session và baseline ban đầu vẫn được giữ đúng.
Bảo vệ code đang làm dở của user
Một coding agent không nên giả định working tree luôn sạch. Trước khi build, workflow ghi nhận:
git status --short --untracked-files=all
git diff --name-status
git diff --cached --name-status
Mục tiêu là phân biệt:
thay đổi có sẵn của user
với:
thay đổi do task hiện tại tạo ra
Build không được reset hoặc discard code của user chỉ để làm diff “đẹp”. Trên repository thật, việc này quan trọng hơn nhiều so với một sandbox demo.
Tại sao runtime chỉ dùng Python standard library?
Tôi cũng muốn kit có thể mang sang project khác mà không kéo theo một stack runtime nặng. Bản thân runtime không yêu cầu một dependency stack lớn. Nó dùng Python standard library để làm baseline cho:
- repository inspection,
- cache,
- Git state,
- dependency graph,
- impact analysis,
- task state,
- verification orchestration.
Khi ecosystem có tool mạnh hơn, kit có thể tận dụng chúng như verification/native tooling. Ví dụ:
Python → Ruff / Pyright / mypy / pytest
Ruby → RuboCop / RSpec
PHP → PHPStan / Pest / PHPUnit
Node → lint / typecheck / test / build scripts
Go → go test
Rust → cargo check / cargo test
Runtime baseline không cố thay thế compiler, framework hay test runner. Nó điều phối chúng.
My Vibe Kit không cố giải quyết điều gì?
My Vibe Kit không nhằm biến coding agent thành một hệ thống tự động hoàn hảo. Static analysis vẫn có giới hạn, nhất là với những cơ chế động của framework. Ví dụ:
- dependency injection động,
- reflection,
- generated code,
- framework registry,
- dynamic import,
- JS/TS alias phức tạp,
- Rails Zeitwerk autoload,
- macro hoặc metaprogramming,
có thể cần native tooling hoặc kiểm tra sâu hơn. Runtime coi dependency scanner là baseline deterministic, không phải sự thật tuyệt đối về mọi runtime behavior. Quan trọng là workflow biết giới hạn của scanner và không biến một suy đoán thành “verified fact”.
Khi nào My Vibe Kit hữu ích nhất?
Kit hữu ích nhất khi bạn:
- dùng coding agent hàng ngày,
- làm việc trên repository tồn tại lâu dài,
- thường xuyên mở session mới,
- không muốn AI đọc lại toàn project,
- muốn kiểm soát scope,
- hay sửa bug/refactor,
- muốn dùng cùng workflow trên nhiều agent,
- và không muốn câu “looks good” được coi là bằng chứng hoàn thành.
Với project nhỏ, workflow vẫn nhẹ. Với project lớn hơn, persistent context và incremental dependency refresh bắt đầu mang lại lợi ích rõ hơn.
Cách sử dụng hằng ngày
Phần lớn task tôi muốn interaction đơn giản như:
Use vibe to implement CSV export for reports.
Hoặc:
Use vibe to fix the crash when history is empty.
Nếu chỉ muốn phân tích:
Use plan to analyze migrating SQLite to PostgreSQL.
Do not edit code yet.
Phần phức tạp nằm dưới workflow, không nằm trong prompt hằng ngày. Tôi muốn câu lệnh gửi cho agent ngắn, còn việc giữ state, dependency và verification do kit lo.
Kết luận
My Vibe Kit bắt đầu từ một nhu cầu khá đơn giản của chính tôi:
Tôi muốn vibe code nhanh, nhưng vẫn biết agent đã đọc gì, sửa gì và kiểm chứng bằng cách nào.
Vì vậy, thay vì tiếp tục thêm prompt và instruction, tôi giữ workflow ở bốn bước:
vibe
↓
plan
↓
build
↓
verify
và đưa các phần có thể deterministic xuống runtime:
context
dependency
impact
cache
task state
verification evidence
Agent vẫn làm phần nó mạnh nhất:
- hiểu yêu cầu,
- reasoning,
- thiết kế thay đổi,
- viết code,
- xử lý lỗi.
Runtime giữ những phần không nên phụ thuộc vào trí nhớ của model: state, dependency, fingerprint và kết quả kiểm chứng. Mục tiêu cuối cùng không phải để AI viết nhiều code hơn, mà để mỗi thay đổi dễ kiểm soát hơn:
đọc ít context hơn
+
sửa đúng scope hơn
+
giữ được trạng thái qua nhiều session
+
biết dependency bị ảnh hưởng
+
có evidence trước khi nói task hoàn thành
Nếu bạn đang dùng Codex, Claude Code hoặc Antigravity trên một codebase thật, source của My Vibe Kit nằm ở:
https://github.com/cuongtobi/my-vibe-kit
Cuong Vuong · Developer, Writer, Builder
Tôi viết về những thứ đã thử, đã xây dựng và những bài học có thể dùng lại trong dự án tiếp theo.
More about me →