Dùng uncut làm harness headless cho coding agent trong CI/CD
uncut là harness coding agent chạy qua stdin/stdout, không tự cắt ngữ cảnh, file hay output lệnh. Công cụ phù hợp để thử trong CI, container và luồng review IaC—nhưng không phải sandbox.
Một job CI vừa fail, nhưng log dài đến mức agent chỉ thấy phần cuối. Nó đưa ra một nguyên nhân nghe hợp lý, trong khi lỗi thật nằm ở đoạn output đã bị cắt trước đó.
Đây là vấn đề mà uncut muốn xử lý theo cách rất trực diện: một harness cho coding agent chạy headless, nhận dữ liệu từ stdin và đưa kết quả ra stdout—không TUI, không telemetry, không tự tóm tắt lịch sử, không tự cắt file hay combined stdout/stderr của lệnh.
Với DevOps/SRE, đây là một mô hình đáng chú ý: agent trở thành một tiến trình có thể ghép vào shell pipeline, CI job, container hoặc môi trường thử nghiệm.
uncut làm gì?
uncut là binary Go tĩnh, làm việc với các endpoint OpenAI-compatible Chat Completions, bao gồm cả server cục bộ. Công cụ có bốn tool:
readfile: đọc toàn bộ file văn bản UTF-8.
writefile: ghi toàn bộ nội dung file và tạo thư mục cha nếu cần.
replace: thay đúng một lần xuất hiện; không khớp hoặc khớp nhiều lần đều báo lỗi.
runcommand: chạy lệnh shell, trả về exit code cùng toàn bộ stdout/stderr kết hợp.
Chế độ headless nghĩa là không có giao diện tương tác. Văn bản cuối được đưa ra stdout. Khi dùng --json, uncut phát các sự kiện NDJSON để công cụ khác có thể xử lý.
Luồng NDJSON gồm các bản ghi user, assistant, assistantmeta, tool, và kết thúc bằng done hoặc error. Trong đó, assistantmeta tách riêng usage và finish reason.
Điểm thực tế cho pipeline:
Có thể pipe git diff, log test hoặc dữ liệu văn bản UTF-8 vào agent.
Có thể dùng NDJSON làm đầu vào cho bước hậu xử lý hoặc lưu artifact.
Nếu provider cắt câu trả lời vì giới hạn output, uncut không coi câu trả lời dở dang là thành công: tiến trình thoát với mã 3.
Nếu chạm giới hạn số lần gọi model qua --max-steps, tiến trình thoát với mã 4.
“Lossless” có nghĩa gì?
“Lossless” không có nghĩa uncut làm context window của model lớn hơn.
Theo README, uncut không tự truncate, summarize hoặc rewrite các prompt UTF-8 hợp lệ, message đã lưu, file văn bản hay output lệnh. Toàn bộ hội thoại được gửi ở mỗi lần gọi model.
Tuy nhiên, provider vẫn có thể từ chối request vì vượt context window hoặc cắt output ở giới hạn riêng của họ. Khi đó, uncut hiển thị lỗi thay vì âm thầm che đi.
Với các luồng review Terraform, Kubernetes manifest hoặc log CI, hành vi “fail rõ ràng” này có thể hữu ích hơn một kết luận được tạo từ dữ liệu không đầy đủ.
Cài đặt và kiểm tra binary
README cung cấp binary cho Linux, macOS và Windows, trên amd64 và arm64. Ví dụ trên Linux:
sh
VERSION=0.1.1
ARCH=amd64 # Use arm64 on ARM64.
curl -fSLo uncut "https://github.com/Balanov/uncut/releases/download/v${VERSION}/uncut-linux-${ARCH}"
mkdir -p "$HOME/.local/bin"
install -m 0755 uncut "$HOME/.local/bin/uncut"
export PATH="$HOME/.local/bin:$PATH"
uncut --version
Mỗi release có checksums.txt. README lưu ý binary chưa được code-sign, nên Gatekeeper hoặc SmartScreen có thể cảnh báo. Hãy kiểm tra SHA-256 trước khi cho executable chạy trong runner:
sh
VERSION=0.1.1
ARCH=amd64
curl -fSLO "https://github.com/Balanov/uncut/releases/download/v${VERSION}/checksums.txt"
grep "uncut-linux-${ARCH}$" checksums.txt | sha256sum -c -
Bạn cũng có thể cài từ Go hoặc build từ mã nguồn:
sh
go install github.com/Balanov/uncut/cmd/uncut@latest
Kết nối model và endpoint
Thiết lập model cùng API key:
sh
export UNCUTAPIKEY="your-api-key"
export UNCUTMODEL="your-model-id"
uncut "Inspect this repository and fix the failing tests"
Với endpoint tương thích OpenAI, đặt thêm base URL:
sh
export UNCUTBASEURL="https://openrouter.ai/api/v1"
uncut cũng hỗ trợ server Ollama cục bộ. README cho biết cấu hình sau đã được smoke-test với qwen3:8b; khả năng tool call vẫn phụ thuộc model đang cài:
sh
ollama pull qwen3:8b
export UNCUTBASEURL="http://localhost:11434/v1"
export UNCUTMODEL="qwen3:8b"
uncut "Explain this repository"
Với endpoint local, mặc định không cần API key.
Pipe diff và log vào agent
Đầu vào từ pipe được nối nguyên văn vào prompt. Ví dụ review thay đổi mà không yêu cầu chỉnh sửa file:
sh
git diff | uncut "Review this diff. Do not edit files."
Hoặc phân tích log test:
sh
cat failing-test.log | uncut "Find the likely cause"
Một prompt review IaC có thể nêu rõ phạm vi mong muốn:
text
Bạn là người review thay đổi hạ tầng.
Chỉ phân tích nội dung diff được cung cấp. Không chỉnh sửa file.
Kiểm tra:
thay đổi quyền truy cập và phạm vi tài nguyên;
cấu hình Kubernetes, Terraform hoặc policy có rủi ro;
biến môi trường, endpoint, volume, network và dependency;
dấu hiệu secret xuất hiện trong mã nguồn hoặc manifest.
Trả về:
các phát hiện và dữ liệu liên quan trong diff;
câu hỏi cần người sở hữu dịch vụ xác nhận;
dữ liệu còn thiếu để kết luận.
Không bịa thông tin không có trong diff.
Prompt chỉ là chỉ dẫn cho model, không phải một cơ chế cô lập hay phê duyệt. Nếu task có thể tác động hệ thống, quyền chạy của tiến trình vẫn là yếu tố quyết định.
JSON, session và giới hạn bước
Khi cần đầu ra có cấu trúc, dùng --json:
sh
uncut --json "Run the tests and fix the failure"
uncut cũng hỗ trợ session JSONL append-only:
sh
uncut --session .uncut/work.jsonl "Start the refactor"
uncut --session .uncut/work.jsonl "Continue with the tests"
Nếu session đã tồn tại, uncut tiếp tục từ toàn bộ lịch sử đã lưu. Record không hợp lệ hoặc dở dang sẽ gây lỗi rõ ràng, thay vì bị âm thầm bỏ qua.
Session có thể chứa source code, output lệnh và secrets. Vì vậy, trước khi dùng session trong CI, cần cân nhắc nơi lưu, quyền truy cập và việc có nên đưa nó vào artifact hay không.
Các cờ đáng chú ý cho runner:
| Cờ | Ý nghĩa |
|---|---|
| --cwd <dir> | Chọn workspace cho file tools và shell command |
| --session <file> | Tạo hoặc tiếp tục session JSONL |
| --max-steps <n> | Giới hạn số lần gọi model; mặc định là 32 |
| --max-tokens <n> | Đặt giới hạn output phía provider |
| --request-timeout <duration> | Timeout cho từng request; mặc định 10m |
| --no-agents | Không đọc AGENTS.md trong workspace |
| --json | Phát sự kiện NDJSON |
Theo mặc định, AGENTS.md ở workspace root được đọc toàn bộ và đưa vào system prompt. Với session được tiếp tục, system message gốc đã lưu sẽ được tái sử dụng.
Không nhầm “lossless” với “an toàn”
uncut không phải sandbox.
Tool file bị giới hạn trong workspace, nhưng runcommand thì không có giới hạn tương tự: nó chạy bằng quyền của user hệ điều hành đang chạy uncut. Trên Unix, lệnh đi qua /bin/sh -c; trên Windows, qua cmd.exe /D /S /C.
README cũng nêu rõ không có popup phê duyệt trước khi agent hành động. Vì vậy, không nên xem prompt như một ranh giới bảo mật.
Với task chưa tin cậy hoặc có khả năng chạy lệnh nguy hiểm, hãy dùng container dùng một lần hoặc môi trường cô lập. Review thay đổi và session trước khi chấp nhận kết quả.
Một checklist vận hành tối thiểu:
[ ] Kiểm tra checksum của binary hoặc build từ source.
[ ] Cấp API key qua cơ chế secret của runner, không hard-code.
[ ] Chạy agent với workspace và quyền tối thiểu.
[ ] Dùng luồng read-only cho review diff, log và manifest khi phù hợp.
[ ] Xử lý mọi exit code khác 0 như trạng thái cần điều tra.
[ ] Không commit session chứa dữ liệu nhạy cảm.
[ ] Kiểm tra thay đổi do AI đề xuất bằng các bước kiểm soát hiện có của đội.
Các mã thoát chính:
| Mã | Ý nghĩa |
|---|---|
| 0 | Hoàn tất với câu trả lời cuối |
| 1 | Lỗi provider, I/O, session hoặc thực thi |
| 2 | Dùng command-line không hợp lệ |
| 3 | Provider trả về finishreason=length hoặc chạm maxtokens |
| 4 | Chạm --max-steps trước khi có câu trả lời cuối |
Kết luận
uncut không thay thế guardrail của CI/CD, sandbox hay quy trình review. Giá trị của nó nằm ở mô hình tối giản và rõ ràng: dữ liệu vào qua stdin, kết quả ra qua stdout, có NDJSON khi cần tích hợp, và lỗi do context hoặc output bị cắt không bị ngụy trang thành thành công.
Với đội ngũ DevOps/SRE đang thử coding agent trong pipeline hoặc container, đó là một đặc tính đáng kiểm tra kỹ—đặc biệt khi log, diff và lịch sử hội thoại là dữ liệu cần được giữ nguyên.