---
title: "§agent-config ◊tag-release: 하네스 투두를 거부하고 CalVer release loop로 묶은 힣 워크플로우"
url: "https://notes.junghanacs.com/botlog/20260531T174826"
author: "Junghan Kim"
date: "2026-05-31T17:48:00+09:00"
lastmod: "2026-06-01T08:32:00+09:00"
tags: ["agent","botlog","git","nixos","workflow"]
description: "하네스마다 다른 TODO 시스템 대신, repo에 사는 4개 텍스트 문서와 4개 도구로 묶은 CalVer 기반 릴리즈 워크플로우. 태그가 0개라 changelog 자동화가 죽어 있던 구조적 원인을 풀고, agent-config SSOT로 멀티 하네스에 배포한 설계 기록."
---

> [!abstract] 이 노트에 대하여
> 
> 이 노트는 "하네스 특화 투두 플랜을 거부한다"는 원칙에서 출발해, 변경 이력을 repo에 사는 텍스트(NEXT/CHANGELOG/ROADMAP/AGENTS)와 도구(commit/gitcli/tag-release)로 묶은 release 워크플로우 설계를 정리한다. nixos-config를 첫 CalVer dogfood로 삼아 실제로 돌려본 결과와, 그 과정에서 드러난 hook의 태그-push false positive까지 기록한다.

## 히스토리

-   [2026-06-14 Sun 11:44] [NEXT.md 핸드오프 패턴 — 검증 기준 내장 + 새 세션이 무너지지 않는 3층 구조 #책갈피](https://notes.junghanacs.com/botlog/20260518T181305) 여기랑 쌍쌍이다.
-   [2026-05-31 Sun 18:06] 추가 — run.sh setup의 dirty-safe managed repo refresh + stale gitcli binary 방지 기록
-   [2026-05-31 Sun 17:48] 생성 — tag-release 스킬 설계 + nixos-config v2026.5.31 첫 dogfood 정리

## 출발점 — 하네스 투두 거부

여러 하네스(pi, Claude Code, OpenCode, Codex)를 오가면 각자의 TODO/플랜 시스템이 따로 논다. Claude Code의 TODO 기능은 꺼 두었고, pi는 날것이며, NEXT.md를 시작한 순간부터 복잡한 트래커를 안 쓴다.

결론은 하나다: **상태는 하네스가 아니라 repo에 사는 텍스트 파일에 둔다.** 하네스가 바뀌어도 파일과 CLI는 그대로다. 이 노트의 워크플로우는 그 원칙의 구체화다.

## 문제 — 태그 0개가 changelog를 죽였다

nixos-config의 CHANGELOG.md는 `[0.3.2] 2026-02-22` 에서 3개월 멈춰 있었다. 게으름이 아니라 구조적 원인이었다.

-   `update-changelog` 스킬(아르민 원본)은 `git describe --tags --abbrev=0` 로 마지막 태그를 baseline 삼아 `git log <tag>..HEAD` 를 수집한다.
-   그런데 nixos-config는 **git 태그가 0개** 였다. baseline 앵커가 없으니 자동화가 애초에 돌 수 없었다.

즉 도구는 있었지만 물고 들어갈 태그가 없었다. "워크플로우가 인지하지 못하는 문서는 생성 즉시 deprecated된다"의 전형.

## 설계 — 4문서 × 4도구, 두 루프

문서의 역할을 직교하게 가른다.

-   `NEXT.md` — 다음 할 일 (휘발성)
-   `CHANGELOG.md` — **무엇이** 바뀌었나 (기계적, 태그 단위)
-   `ROADMAP.md` — **왜/어떻게** 여기까지 왔나 (서사, 수기)
-   `AGENTS.md` — 현재 운영 상태 (영속 baseline)

도구는 두 개의 루프로 묶는다.

-   **일상 루프** (고빈도): 작업 → `commit` 스킬 → 커밋 후 agenda stamp → NEXT.md 갱신
-   **태그 루프** (저빈도): `gitcli` 로 지난 태그 이후 커밋 집계 → CHANGELOG 갱신 → CalVer 태그 컷(`tag-release` 스킬) → ROADMAP 스냅샷

CHANGELOG가 SSOT이고, GitHub 릴리즈 본문은 거기서 추출하는 render다.

## 결정들

-   `update-changelog` → `tag-release` 로 rename하고 CalVer 태그 컷 절차를 흡수했다. 새 스킬은 0개 — 기존 스킬 확장.
-   `commit` 스킬은 살리되, AGENTS.md의 "Agenda Stamp on Git Commit" 절차(48줄 bash 블록)를 `commit` 스킬로 내렸다. 항상 로드되는 AGENTS.md는 436→397줄로 슬림화. commit 시점에만 로드되는 스킬이 지침을 전달한다.
-   **위험 비대칭** 때문에 commit과 release를 한 스킬에 안 섞었다: commit은 고빈도·저위험·멱등(로컬), release는 저빈도·고위험·외부 발행(push/tag, 되돌리기 어려움).
-   SemVer를 폐기하고 **CalVer** 를 채택했다. 인프라/config repo는 major/minor/patch 의미가 약하다 — NixOS 자체가 CalVer다. 태그 형식은 OpenClaw 생태계와 맞춰 `vYYYY.M.D` (선택적 `-beta.N=/`-rc.N=).
-   CalVer의 함정 하나: zero-pad가 없는 `vYYYY.M.D` 는 plain 문자열 정렬이 시간순과 어긋난다(`v2026.5.9` &gt; `v2026.5.31`). version-aware 정렬(`git describe`, `--sort=version:refname`)만 쓰고 plain `sort` 를 금하는 가드를 스킬에 박았다.

## gitcli 실버그 수정

태그 루프가 `gitcli log <repo> --from <date>` 로 재료를 모으는데, 실제로 돌려보니 `--from` 단독으로는 동작하지 않고 기본 7일로 떨어졌다(`--to` 없으면 무시). CalVer 태그 날짜 파싱(`v2026.5.30-beta.1` → `2026-05-30`)도 함께 추가했다. 설계가 도구의 숨은 버그를 드러낸 자리.

## 첫 dogfood — nixos-config v2026.5.31

-   CHANGELOG를 CalVer로 전환. `## v2026.5.31` 첫 스냅샷에 3개월(213커밋)을 Added/Changed/Fixed로 압축하고, OpenClaw 버전 hop 디테일은 ROADMAP 참조로 위임. 기존 SemVer `0.1.0~0.3.2` 라인은 역사로 보존.
-   ROADMAP "현재 위치"를 `v2026.5.31` 스냅샷으로: 4 디바이스(oracle/nuc/laptop/thinkpad) + Docker 10 스택 = "oracle를 통째로 재현하는 공개 인프라"라는 정체성을 전면에.
-   NEXT에 26.05 업그레이드 항목(25.11 EOL 2026-06-30).

## 발견 — 태그 push hook false positive

`git push origin v2026.5.31` 이 글로벌 안전 hook에 막혔다. 사유는 `machines/gpu-03.nix` 의 식별어인데, 이 파일은 이미 origin/main에 있는 grandfathered 내용이고 태그가 가리키는 커밋도 이미 push된 `68a0baf` 였다. 태그가 새로 도입하는 변경은 0줄이어야 정상.

원인은 태그-push 시 hook이 remote-reachable 커밋을 baseline에서 빼지 못하고 넓은 범위를 added로 재스캔하는 것. `AGENT_ALLOW_UNSAFE_COMMIT` 은 정책상 에이전트가 쓰지 않으므로 STOP하고 GLG에게 보고했다. 도구 underperformance는 도구 이슈로 기록한다는 원칙의 사례.

## 멀티 하네스 SSOT

이 모든 변경은 nixos-config 한 곳이 아니라 `agent-config` 에 산다. `run.sh setup` 이 skills 디렉토리를 스캔해 pi / Claude plugin / Codex / OpenCode 등 모든 하네스로 심볼릭 링크한다. 한 곳을 고치면 전 하네스에 퍼진다 — 그래서 "여기만 잘하면 소용없다"가 아니라 "여기를 고치면 전부 고쳐진다".

## 관련 노트

-   nixos-config `ROADMAP.md` / `CHANGELOG.md` (repo 내, v2026.5.31)
-   agent-config `skills/tag-release/` / `skills/commit/` (워크플로우 SSOT)

## [2026-05-31 Sun] setup freshness — stale binary를 빌드하지 않기

이번 루프의 마지막 퍼즐은 `run.sh setup` 이었다. 기존 철학은 "setup은 pull하지 않는다"였고, 이는 작업 중인 외부 repo를 건드리지 않기 위한 안전장치였다. 하지만 그 결과 Oracle/다른 장비에서 `gitcli` repo가 stale이면, `setup` 이 **stale source를 그대로 다시 빌드** 하는 문제가 생겼다. GLG가 매번 "먼저 update"를 기억해야 한다면 워크플로우 실패다.

정리한 원칙:

-   **dirty repo는 절대 pull하지 않는다** — 수정 중인 작업은 보호한다.
-   **clean한 managed build input은 setup이 fast-forward refresh한다** — 업데이트된 것은 가져와서 빌드한다.
-   opt-out은 `AGENT_CONFIG_SETUP_NO_UPDATE=1 ./run.sh setup`.

구현: `agent-config/run.sh` 의 `setup` 앞단에 self-refresh와 managed repo refresh를 추가했다. `agent-config` 자신이 clean + behind이면 `git pull --ff-only` 후 새 `run.sh` 로 `exec` 재시작한다. `gitcli/denotecli/lifetract/dictcli/zotero-config` 같은 managed repo는 clean일 때만 fetch+fast-forward하고, dirty/diverged/no-upstream이면 warning 후 local source로 build한다.

검증: `./run.sh setup` 에서 `gitcli: up to date` 후 build, `Binaries: 6/6`, `gitcli --version => 0.3.0`. 커밋 `4a9b5d4 chore(setup): refresh clean managed repos` 로 agent-config에 반영하고 push/stamp 완료.

이 결정은 "setup이 작업 중인 repo를 건드리지 않는다"는 기존 철학의 폐기가 아니라, 그 핵심을 더 정확히 구현한 것이다. 보호 대상은 dirty worktree이고, stale dependency는 보호 대상이 아니다.
