Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: test

# git-trail 자체의 개발용 CI(GF-21, decision-8). 컨슈머에 배포하는 verify.yml과
# coding-agent-git-commit-tool 자체의 개발용 CI(GF-21, decision-8). 컨슈머에 배포하는 verify.yml과
# 달리 이건 이 저장소 자신의 훅 코드 품질만 검사한다 — 훅도 테스트도 Python 표준
# 라이브러리만 쓰므로(decision-16, decision-21) 테스트 프레임워크를 따로 설치하는
# 스텝이 없다. 아래 ruff 설치는 이 저장소 자신의 Python 코드를 검사하는 개발 도구다 —
Expand Down
2 changes: 1 addition & 1 deletion .gitmessage
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@
#
# ── 이 템플릿 사용법 ──
# git config commit.template .gitmessage
# (git-trail install.sh를 사용하면 자동으로 설정됩니다 — GF-8 참고)
# (coding-agent-git-commit-tool install.sh를 사용하면 자동으로 설정됩니다 — GF-8 참고)
29 changes: 16 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
<div align="center">

# 👣 git-trail
# 🤖 coding-agent-git-commit-tool

**git 이력을 감사 추적(audit trail)으로 만드는 도구 — 커밋 형식 · 출처 기록(provenance) · 이력 불변**
**코딩 에이전트의 git 커밋을 검사하고, 누가·어떤 모델로·무슨 태스크로·얼마를 들여 만들었는지 커밋에 자동으로 기록하는 git 훅**

[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
[![Hooks: Python 3](https://img.shields.io/badge/hooks-Python%203-3776ab.svg)](./hooks/)
[![Installer: POSIX sh](https://img.shields.io/badge/installer-POSIX%20sh-89e051.svg)](./install.sh)
[![Requires: git + python3](https://img.shields.io/badge/requires-git%20%2B%20python3-brightgreen.svg)](#-필요조건을-말씀드립니다)

에이전트와 사람이 남기는 커밋을 정해진 양식으로 쓰고, 누가·무엇으로·얼마를 들여
만들었는지 자동으로 기록하고, 한 번 남긴 기록은 다시 쓰지 않게 지키는 도구입니다.
커밋할 때마다 두 가지를 합니다. 메시지 규칙(제목 형식·길이, 태스크 번호가 든 브랜치)을
검사해 어기면 커밋을 거부하고, 통과한 커밋 끝에 작성자·AI 도구와 모델·태스크·토큰
사용량을 트레일러로 자동으로 붙입니다. 한 번 남긴 이력은 다시 쓰지 않는다는 원칙도
지향하지만, 지금은 GitHub 원격 설정으로만 지키고 있습니다.
`core.hooksPath` · `git interpret-trailers` 등 **git 자체 기능**으로 동작합니다.
훅은 Python 3 표준 라이브러리만 쓰므로 설치할 패키지는 없지만, `python3` 자체는
필요합니다([필요조건](#-필요조건을-말씀드립니다)).
Expand Down Expand Up @@ -66,7 +68,7 @@ Signed-off-by: cpu-once <231006716+cpu-once@users.noreply.github.com>
| `Tokens-Used` | 이 커밋에 든 토큰(`in=<입력> out=<출력>`). 작업 비용을 이력에서 읽게 합니다 | `post-commit` · 이 커밋이 바꾼 파일을 건드린 응답의 토큰 합(귀속), 델타 아님(decision-27) | 서버 발급 사실(Claude Code 한정), **측정 방법론은 실험 단계** |
| `Tool-Calls` | 이 커밋의 파일을 건드린 도구 호출 수 | `post-commit` · 귀속된 응답에서 대상 파일을 건드린 `tool_use` 블록 개수 | 위와 동일 |
| `Co-Authored-By` | 공동저자 귀속 | `post-commit` · `AI-Tool`이 `claude-code`일 때만 | 자동 |
| `Hooks-Commit` | 이 커밋을 검사한 git-trail 자체의 버전. 훅에 버그가 있었을 때 어느 커밋들이 그 훅을 거쳤는지 역추적합니다 | `post-commit` · 훅 클론의 `rev-parse --short HEAD` | 완전 자동, 모든 커밋 |
| `Hooks-Commit` | 이 커밋을 검사한 coding-agent-git-commit-tool 자체의 버전. 훅에 버그가 있었을 때 어느 커밋들이 그 훅을 거쳤는지 역추적합니다 | `post-commit` · 훅 클론의 `rev-parse --short HEAD` | 완전 자동, 모든 커밋 |
| `Signed-off-by` | 커미터 정보(DCO 관례) | `post-commit` · `git log -1 --format='%cn <%ce>'` | 완전 자동, 모든 커밋 |
| `Verify-Bypassed` | `--no-verify`로 검사를 건너뛴 사실. 우회를 막지는 못하니 대신 기록합니다(decision-3) | `post-commit` · `prepare-commit-msg`가 남긴 검증 마커의 **부재** | 자동 |
| `Fixes` | 이 버그를 만든 커밋 | **사람이 씀**(원인 커밋을 아는 경우만) · `commit-msg`가 해시 실재를 검증 | 검증됨 |
Expand All @@ -79,10 +81,10 @@ Signed-off-by: cpu-once <231006716+cpu-once@users.noreply.github.com>
## 🪝 커밋 한 번에 훅이 도는 순서

> 공식 문서: [githooks(5)](https://git-scm.com/docs/githooks). git이 제공하는 훅은 28개이고,
> git-trail의 훅은 지금 커밋 단계만 다룹니다. push된 이력의 보호는 원격 설정이 맡습니다
> coding-agent-git-commit-tool의 훅은 지금 커밋 단계만 다룹니다. push된 이력의 보호는 원격 설정이 맡습니다
> ([다루는 범위](#-다루는-범위)).

| 순서 | 훅 | 커밋 객체가 있는가 | `--no-verify`로 건너뛰나 | git-trail이 하는 일 |
| 순서 | 훅 | 커밋 객체가 있는가 | `--no-verify`로 건너뛰나 | coding-agent-git-commit-tool이 하는 일 |
| ---- | ------------------------------------------------ | ------------------ | ------------------------ | ------------------------------------------------------------------------------------ |
| 1 | [`prepare-commit-msg`](hooks/prepare-commit-msg) | 아직 없음 | **건너뛸 수 없음** | 재생·병합 커밋 면제, 에디터 경로 거부, 검증 마커 기록 |
| 2 | (에디터) | 아직 없음 | — | 사람이 메시지를 씁니다. 훅보다 **뒤**라서 1번은 최종 메시지를 볼 수 없습니다 |
Expand Down Expand Up @@ -116,10 +118,10 @@ attestation(서명된 증명)은 아직 없고, audit(사후 검사)은 커밋

**언어별 lint는 다루지 않습니다**(decision-23) — 세 기둥 어디에도 속하지 않고, 컨슈머에게
npm/ruff/clang-format 같은 도구를 전제하게 만듭니다. 언어 검사가 필요하면 CI에서 돌리시기
바랍니다. git-trail이 `core.hooksPath`를 점유하므로 그 저장소의 `.git/hooks/*`는
바랍니다. coding-agent-git-commit-tool이 `core.hooksPath`를 점유하므로 그 저장소의 `.git/hooks/*`는
무시되고, 자기 훅과 함께 쓰는 방법은 아직 정하지 않았습니다.

> 이름은 git-format → git-logbook → git-trail 순으로 바뀌었습니다(decision-25, decision-26). 설정 키와 파일명
> 이름은 git-format → git-logbook → git-trail → coding-agent-git-commit-tool 순으로 바뀌었습니다(decision-25, decision-26, decision-29). 설정 키와 파일명
> (`gitformat.*`, `gitformat.conf`, `.gitformat-*`)은 기존 설치를 깨지 않도록 아직 예전 이름입니다(GF-133).

구성은 Python 훅 + 설정 파일 하나(`hooks/gitformat.conf`) + POSIX sh 설치
Expand Down Expand Up @@ -156,17 +158,18 @@ python3는 이런 환경에서 보이지 않을 수 있습니다.
### 기존 저장소에 적용하는 방법입니다

```sh
git clone https://github.com/coralstay/git-trail.git ~/git-trail # 원하는 위치에 한 번만 클론
git clone https://github.com/coralstay/coding-agent-git-commit-tool.git ~/coding-agent-git-commit-tool # 원하는 위치에 한 번만 클론
cd ~/my-project
~/git-trail/install.sh
~/coding-agent-git-commit-tool/install.sh
```

대상 디렉터리를 인자로 주셔도 됩니다: `~/git-trail/install.sh ~/my-project`.
대상 디렉터리를 인자로 주셔도 됩니다: `~/coding-agent-git-commit-tool/install.sh ~/my-project`.
클론 위치와 폴더 이름은 자유롭게 정하셔도 됩니다 — `install.sh`는 자기가 놓인 클론의 `hooks/`를 씁니다.

### 앞으로 만들 모든 새 저장소에 자동 적용하는 방법입니다

```sh
~/git-trail/install.sh --global
~/coding-agent-git-commit-tool/install.sh --global
```

`git init`/`git clone`을 실행할 때마다 훅과 커밋 템플릿이 자동으로 심어집니다
Expand Down
2 changes: 1 addition & 1 deletion backlog/config.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project_name: "git-trail"
project_name: "coding-agent-git-commit-tool"
default_status: "To Do"
statuses: ["To Do", "In Progress", "Done"]
labels: []
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
id: decision-28
title: Signed-off-by 유지는 유저가 직접 확정했다 (decision-25 보완)
date: '2026-10-03 12:48'
status: accepted
---
## Context

decision-19(2026-09-25)가 `Signed-off-by` 제거를 정했지만, 그 실행을 맡은 GF-128이 아직
To Do라 `post-commit`은 계속 이 트레일러를 붙여 왔다. 그 사이 decision-25(2026-10-03)가
"문서끼리 충돌하면 최근 문서를 우선한다"는 규칙을 적용해 제거 조항을 대체하고 유지로
정했다. 근거는 decision-24·DRAFT-19가 `Signed-off-by`와 실제 커미터의 불일치를 이력
재작성의 증거로 쓴다는 것이었다.

그 규칙은 유저가 바로 이 충돌(decision-19 vs DRAFT-19)을 두고 직접 준 것이다. 다만 규칙의
결과가 "`Signed-off-by`가 계속 붙는다"는 점은 그때 분명히 드러내지 않았다. 2026-10-03 유저가 "지웠는데 왜 남아 있나"라고 물어 경위를
설명했고, 유저가 직접 유지를 골랐다.

## Decision

**`Signed-off-by`는 유지한다 — 유저가 직접 확정했다.** decision-25의 유지 조항과 근거는
그대로이고, 이 decision은 그 판단이 유저 확인을 거쳤다는 사실만 보탠다.

## Consequences

- GF-128 AC #10("Signed-off-by는 계속 삽입한다")이 그대로 유효하다. 설명 본문의
"Signed-off-by를 없앤다"는 GF-128 코멘트 #1과 이 decision으로 대체된다.
- 이 트레일러를 실제로 대조하는 코드는 아직 없다(DRAFT-19가 draft 상태). 그 전까지는
사람이 `git log`로 커미터와 비교할 때만 쓰인다.
- 나중에 같은 질문이 나오면 decision-19가 아니라 이 decision을 본다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
id: decision-29
title: 이름을 coding-agent-git-commit-tool로 바꾼다 (decision-26의 이름 조항 대체)
date: '2026-10-03 13:11'
status: accepted
---
## Context

decision-26(2026-10-03)이 이름을 git-trail로 정했다. 같은 날 유저가 "와닿지 않는다"고 했고,
이름을 다시 고르기 전에 이 프로젝트가 무엇을 하는지부터 다시 정리했다. 실제로 쓰면서
체감하는 일은 두 가지다.

- 커밋 메시지 규칙을 검사해 어기면 커밋을 거부한다(`prepare-commit-msg`, `commit-msg`).
- 커밋마다 작성자·AI 도구·모델·태스크·토큰을 트레일러로 자동 기록한다(`post-commit`).

trail·logbook·ledger·hallmark처럼 "지울 수 없는 기록"에 기댄 이름은, 이력 불변 기둥이 아직
코드로 구현되지 않은 상태(DRAFT-18·19)에서 이 두 가지를 떠올리게 하지 못했다.

후보로 git-claude도 나왔지만, 유저는 범위를 Claude 전용으로 좁히지 않고 여러 AI 도구를
계속 지원하기로 했다. 이어서 agent-commit을 검토했으나 "에이전트가 커밋을 대신 만들어
주는 도구"로 읽힐 수 있었다. 유저가 "헷갈리지 않게" 하는 일을 그대로 적은 이름을 골랐다.

## Decision

**이름을 coding-agent-git-commit-tool로 바꾼다.** 코딩 에이전트가 만드는 git 커밋을 다루는
도구라는 뜻이다. decision-26의 이름 조항만 대체하고, decision-25의 목적 세 기둥과 decision-26의
용어 설명(doc-21 개념 지도)은 그대로 유효하다.

**범위는 범용으로 유지한다.** Claude Code 이외의 AI 도구 지원(`gitformat.knownModel`의 다른
모델, `AI-Model` 게이트, decision-15·17)은 이름 때문에 버리지 않는다.

로컬 폴더, GitHub 저장소, 문서를 모두 새 이름으로 바꾼다(유저 지시). GitHub 저장소는
coralstay/git-trail → coralstay/coding-agent-git-commit-tool로 rename하고, 예전 이름 세 개는
GitHub이 리다이렉트한다.

## Consequences

- 표시 이름만 바뀐다. 설정 키·파일명(`gitformat.*`)은 GF-133, 태스크 접두어 GF와 지난 기록
본문은 decision-25·26과 같은 이유로 그대로 둔다.
- 로컬 폴더가 옮겨지면 Claude Code의 프로젝트 경로가 바뀐다. 트랜스크립트와 메모리 위치가
경로에서 파생되므로, 이동은 병합 뒤 마지막에 하고 메모리는 새 경로로 복사한다.
`core.hooksPath`를 이 폴더로 둔 저장소(이 저장소, agent-orchestartor)는 다시 설치해야 한다.
- 이름이 길다. 명령 예시에서는 클론 위치를 짧게 잡아도 된다고 README에 안내한다.

20 changes: 10 additions & 10 deletions backlog/docs/doc-1 - 설치-가이드.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@ id: doc-1
title: 설치 가이드
type: guide
created_date: '2026-09-19 05:27'
updated_date: '2026-10-03 07:30'
updated_date: '2026-10-03 13:12'
---
## 🚀 설치

### 기존 저장소에 적용

```sh
git clone https://github.com/coralstay/git-trail.git ~/git-trail # 원하는 위치에 한 번만 클론
git clone https://github.com/coralstay/coding-agent-git-commit-tool.git ~/coding-agent-git-commit-tool # 원하는 위치에 한 번만 클론
cd ~/my-project
~/git-trail/install.sh
~/coding-agent-git-commit-tool/install.sh
```

대상 디렉터리를 인자로 줘도 됩니다: `~/git-trail/install.sh ~/my-project`.
대상 디렉터리를 인자로 줘도 됩니다: `~/coding-agent-git-commit-tool/install.sh ~/my-project`.

### 앞으로 만들 모든 새 저장소에 자동 적용

```sh
~/git-trail/install.sh --global
~/coding-agent-git-commit-tool/install.sh --global
```

`git init`/`git clone`을 실행할 때마다 훅과 커밋 템플릿이 자동으로 심어집니다
Expand All @@ -35,18 +35,18 @@ cd ~/my-project

| 대상 | 명령 | 효과 |
| ----------------- | -------------------------------------------------------------- | ------------------------------------------ |
| 로컬(대상 저장소) | `git config core.hooksPath <git-trail>/hooks` | `.git/hooks/`의 기존 로컬 훅을 완전히 대체 |
| 로컬(대상 저장소) | `git config commit.template <git-trail>/.gitmessage` | 커밋 에디터에 스켈레톤 표시 |
| 전역(`--global`) | `git config --global init.templateDir <git-trail>/template` | 이후 모든 신규 저장소에 자동 적용 |
| 전역(`--global`) | `git config --global commit.template <git-trail>/.gitmessage` | 위와 동일, 전역 기본값 |
| 로컬(대상 저장소) | `git config core.hooksPath <coding-agent-git-commit-tool>/hooks` | `.git/hooks/`의 기존 로컬 훅을 완전히 대체 |
| 로컬(대상 저장소) | `git config commit.template <coding-agent-git-commit-tool>/.gitmessage` | 커밋 에디터에 스켈레톤 표시 |
| 전역(`--global`) | `git config --global init.templateDir <coding-agent-git-commit-tool>/template` | 이후 모든 신규 저장소에 자동 적용 |
| 전역(`--global`) | `git config --global commit.template <coding-agent-git-commit-tool>/.gitmessage` | 위와 동일, 전역 기본값 |

**실행 중 새로 생기는 파일**

| 파일/디렉터리 | 위치 | 언제 | 비고 |
| ------------------------- | ---------------------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------- |
| `.gitformat-verified` | `<대상 저장소>/.git/` | `pre-commit` 통과 시 생성, `post-commit`이 곧 삭제 | 커밋 사이에 남지 않는 임시 마커 |
| `.gitformat-token-attributed` | `<대상 저장소>/.git/` | Claude Code 실측 성공 시에만 `post-commit`이 갱신(`unavailable`일 때는 갱신 안 함) | `Tokens-Used`/`Tool-Calls` 귀속 기록(첫 줄 세션 ID, 이후 이미 귀속된 응답 키 — 세션이 바뀌면 새로 시작, GF-129), 커밋 간 유지됨. 예전 델타 커서 `.gitformat-token-cursor`는 더 쓰지 않으며 측정 성공 시 지워짐 |
| `template/hooks/*` | 이 git-trail 클론 자신의 `template/` 안 | `install.sh --global` 실행 시 | 클론 위치를 가리키는 심볼릭 링크, 커밋 안 됨(`.gitignore`) |
| `template/hooks/*` | 이 coding-agent-git-commit-tool 클론 자신의 `template/` 안 | `install.sh --global` 실행 시 | 클론 위치를 가리키는 심볼릭 링크, 커밋 안 됨(`.gitignore`) |

**커밋 자체가 바뀌는 경우**: `post-commit`이 조건에 따라 `git commit --amend`로
방금 만든 커밋의 footer에 트레일러를 추가합니다(README의 "훅 생애주기" 섹션과
Expand Down
Loading
Loading