블로그를 리뉴얼하면서 화면을 Figma에 그리고 있다. 내가 자는 동안 에이전트가 화면을 만들고, 아침에 내가 Figma를 열어 댓글을 단다. 그러면 에이전트가 그걸 읽고 고친다.

이 왕복이 몇 번 돌자 문제가 하나 생겼다. 캔버스에 핀이 쌓이는데, 어느 게 끝났고 어느 게 남았는지 알 수 없다.

핀 하나를 열어야 안에 뭐가 적혔는지 보인다. 열두 개가 흩어져 있으면 열두 번 열어야 한다. 그러면 「오늘 뭘 봐야 하나」에 답하는 데만 시간이 다 간다.

정해야 했던 건 이거였다 — 에이전트가 어디까지 하고 어디서 멈추는가.

이 글은 내가 한 번 잘못 고르고 반나절 만에 뒤집은 기록이다. 뒤집은 이유가 결론보다 중요하다.


먼저: Figma REST API에는 댓글 해결 처리가 없다

가장 자연스러운 답은 “반영하면 해결 처리하면 되지”다. Figma 화면에는 체크 버튼이 있고, 누르면 핀이 사라진다.

그런데 에이전트는 그 버튼을 API로 못 누른다. 추측하지 않고 직접 두드려봤다.

GET    /v1/files/:key/comments                 200   읽기 된다
POST   /v1/files/:key/comments                 200   쓰기 된다 (답글은 comment_id)
DELETE /v1/files/:key/comments/:id             200   삭제 된다
POST   /v1/files/:key/comments/:id/reactions   200   반응 된다

PUT    /v1/files/:key/comments/:id             404
POST   /v1/files/:key/comments/:id/resolve     404
PATCH  /v1/files/:key/comments/:id             404

읽기·쓰기·삭제·반응은 되는데 해결 처리만 없다. 읽을 때 내려오는 resolved_at 값은 보이기만 하고 고칠 수 없는 값이다.

버려도 되는 시험용 댓글을 하나 만들어 두드리고 지우는 방식으로 쟀다. 실제로 달려 있던 댓글은 건드리지 않았다.

반응은 이모지 문자를 받지 않는다. :eyes:처럼 콜론으로 감싼 이름만 200이 오고, 문자를 그대로 넣으면 400 Invalid emoji가 온다.


먼저: 답글도 반응도 핀 겉모습을 바꾸지 않는다

해결 처리가 막혔으니 다음 후보는 답글이었다. 반영이 끝나면 그 댓글에 “고쳤다”고 달아두면 되지 않나.

핀 밖에서는 안 보인다. 답글은 핀 안에 들어간다. 반응도 마찬가지다. :+1:을 붙여도 캔버스에 찍힌 동그라미는 똑같이 생겼다.

여기서 제약이 하나로 정리됐다.

핀의 겉모습을 바꾸는 수단은 해결 처리뿐이고, 그건 API에 없다. 에이전트가 API로 핀을 없앨 수 있는 방법은 삭제 하나뿐이다.

이 문장이 나를 잘못된 결론으로 데려갔다. 핀을 없애는 게 목표라고 전제했기 때문이다.


원칙 1. 댓글은 REST API로 읽고 토큰은 .env에 둔다

플러그인 API로는 못 읽는다. 댓글에 닿는 기능 자체가 없어서, 처음에는 내용을 말로 받아 반영했다.

set -a; . ./.env; set +a
curl -s -H "X-Figma-Token: $FIGMA_TOKEN" \
  "https://api.figma.com/v1/files/<FILE_KEY>/comments"

정해야 했던 건 이거였다 — 토큰을 어디 두는가.

안 A — 환경변수로 셸에 심는다. 얻는 것은 파일이 아예 없다는 것이다. 버린 이유는 클론마다 사람이 다시 심어야 하고, 안 심었을 때 「토큰이 없다」가 아니라 「댓글이 0개다」로 보인다는 것이다. 빈 결과와 인증 실패가 구분되지 않는다.

골랐다 — 안 B, 저장소 루트의 .env 파일. 에이전트가 경로를 알고, 없으면 파일이 없다고 바로 말한다. 대신 .gitignore에 넣는 일이 따라붙는다. 실제로 이 저장소는 .env가 무시 목록에 없어서, git add . 한 번이면 토큰이 올라갈 상태였다.

토큰 값은 화면에 찍지 않고 파일로도 남기지 않는다. 명령 안에서만 쓴다.


원칙 2. 반영하면 그 댓글에 답글로 무엇을 고쳤는지 적는다

고친 뒤에 아무것도 안 남기면, 요청한 사람은 핀을 열어도 자기가 쓴 글만 본다.

curl -s -X POST -H "X-Figma-Token: $FIGMA_TOKEN" -H "Content-Type: application/json" \
  -d "{\"message\":\"...\",\"comment_id\":\"<COMMENT_ID>\"}" \
  "https://api.figma.com/v1/files/<FILE_KEY>/comments"

「반영했습니다」만 적지 않는다. 그러면 확인하는 쪽이 화면을 처음부터 다시 봐야 한다. 무엇을 어떻게 바꿨는지가 있으면 그 부분만 보고 판정할 수 있다.


원칙 3. 에이전트는 댓글을 지우지 않는다

이게 이 표준의 핵심이고, 내가 한 번 반대로 정했던 자리다.

정해야 했던 건 이거였다 — 반영이 끝난 댓글을 누가 어떻게 없애는가.

안 A — 이력 프레임을 만들고 핀은 그대로 둔다. 얻는 것은 왕복이 한 파일에서 다 보인다는 것이다. 그때 버린 이유는 핀이 그대로 남아 표와 화면 두 곳을 대조해야 한다는 것이었다.

안 B — 에이전트가 답글을 달고 사람이 해결을 누른다. 얻는 것은 만들 게 없다는 것이다. Figma가 원래 그렇게 쓰라고 만든 기능이고 해결된 핀은 진짜로 사라진다. 그때 버린 이유는 리뷰 한 번에 사람 손이 두 번 간다는 것이었다.

안 C — 반영이 끝나면 에이전트가 지운다. 얻는 것은 「화면에 남은 핀 = 아직 안 한 일」이 대조도 사람 손도 없이 항상 참이라는 것이다. 안 A는 대조가 필요하고 안 B는 사람이 안 누르면 깨지는데, 삭제만 그 상태를 스스로 유지한다.

나는 안 C를 골랐고, 실제로 두 건을 지웠고, 반나절 만에 뒤집었다.

골랐다 — 안 B에 안 A의 이력표를 붙인 형태. 안 C의 삭제만 버린다. 근거는 다음 섹션이다.

대가는 있다. 사람이 확인을 안 누르면 핀이 쌓인다. 그건 프로세스의 결함이 아니라 확인이 밀린 상태 그대로다. 쌓인 핀이 「얼마나 밀렸나」를 정직하게 보여준다.


원칙 3의 근거. 「반영했다」와 「요청대로 됐다」는 다르다

삭제는 에이전트 자신의 판정으로 핀을 없앤다. 요청한 사람은 그게 요청대로 됐는지 아직 못 봤는데 핀이 사라진다. 그 순간 확인 단계가 통째로 증발한다.

디자인에서 이 간극은 유난히 크다. “카드 배경에 이미지를 깔아달라”는 요청 하나에 정답이 하나가 아니다. 실제로 이번에도 이렇게 갔다.

1차   블러 9~14 + 어두운 막 0.70      →  "지금 너무 흐려서 배경이 아예 안 보여"
2차   블러 제거 + 막 0.55~0.80 사다리   →  "더 어둡게 가자"
3차   막 0.85                        →  확정

세 번 중 두 번은 「반영은 됐는데 원하는 게 아니었다」였다. 1차 반영 뒤에 댓글을 지웠다면 「배경 깔기 완료」로 적힌 이력만 남았을 것이다.

코드라면 테스트가 이 판정을 대신한다. 디자인에는 그런 게 없다. 판정자가 사람뿐이다. 그러면 핀을 닫는 권한도 사람에게 있어야 한다.

그리고 전제가 바뀌자 버렸던 두 안의 버린 이유가 동시에 무효가 됐다. 안 B의 「손이 두 번 간다」는 그게 바로 확인이었고, 안 A의 「핀이 남는다」는 확인 전까지 남아야 하는 것이었다.


원칙 4. 이력에 요청을 원문 그대로 적는다

답글은 핀 안에 있어서 훑을 수 없다. 그래서 이력표가 따로 있어야 한다.

이력표는 지우기 위한 게 아니라 확인하기 위한 것이다. 핀 열두 개를 하나씩 열지 않고, 표 한 장에서 무엇이 요청됐고 무엇이 반영됐는지 훑고 어느 것부터 볼지 고른다. 안 B의 원래 단점이 여기서 풀린다.

표는 다섯 칸이다 — 날짜 · 화면 · 요청 원문 · 반영 · 상태.

  • 요약하지 않는다. 오타도 그대로 옮긴다. 요약하면 나중에 “이게 무슨 뜻이었지”가 복원되지 않는다
  • 화면은 프레임 이름과 node id를 같이 적는다. 이름은 바뀌지만 id는 안 바뀐다
  • 상태는 셋뿐이다waiting(답글·확인 대기) · done(사람이 해결을 눌렀다) · deleted(옛 방식으로 지운 것)

마지막 값이 있는 이유는 이 규칙을 정하기 전에 내가 두 건을 지웠기 때문이다. 지운 건 복구되지 않으니 그렇게 표시해 남겼다.


원칙 5. 이력은 디자인 파일이 아니라 저장소에 둔다

처음엔 이 표를 Figma 안에 프레임으로 만들었다. 「파일 하나만 열면 다 보인다」가 좋아 보였다. 옮겼다. 이유는 셋이다.

하나 — 기록이 두 곳에 살면 조용히 어긋난다. 답글은 댓글 스레드에 있고 표는 캔버스에 있는데, 한쪽만 고치면 아무도 모른다.

둘 — 캔버스 안 글자는 grep에 안 잡힌다. 저장소를 뒤져 “무엇이 남았나”에 답하는 경로 밖에 있어서, 다음 세션의 에이전트가 못 찾는다.

셋 — 디자인 파일은 갈아엎힌다. 프레임을 지우고 다시 만드는 게 작업이라, 거기 붙은 기록도 같이 날아갈 위험을 늘 안는다. 이 리뉴얼에서만 섹션을 두 번 통째로 재배치했다.

데이터 파일과 표시용 페이지를 나눈다. 이 블로그는 이렇게 뒀다.

_data/design-review.yml    항목. 에이전트는 이것만 읽는다
_pages/design-review.md    표를 그리는 템플릿 → /design-review/

항목을 적거나 상태를 바꿀 때는 표시용이 아니라 데이터 파일을 고친다. 표시용에는 마크업뿐이라 한 건 확인하려고 읽으면 마크업까지 따라온다.


판단 기준 정리

질문 결론
댓글을 플러그인 API로 읽을 수 있나 없다 REST API + .env 토큰
해결 처리를 API로 할 수 있나 없다. 세 경로 다 404 에이전트는 핀을 닫을 수 없다
그럼 에이전트가 지우면 되나 요청자가 결과를 못 본 채 핀이 사라진다 지우지 않는다
「반영했다」로 충분한가 세 번 중 두 번 다시 갔다 사람이 판정한다
확인하는 손이 낭비인가 아니다. 그게 확인이다 없애지 않는다
핀이 남는 게 문제인가 확인할 때까지는 남는 게 맞다 쌓인 핀 = 밀린 만큼
답글만 달면 되나 핀 안에 있어 훑을 수 없다 이력표를 따로 둔다
이력을 디자인 파일에 둘까 어긋나고 · grep 안 되고 · 날아간다 저장소에 둔다

이 표준을 정하기까지

시작은 댓글을 못 읽는 것이었다. 리뷰를 댓글로 남겼다는 말을 듣고 도구를 찾았는데, 플러그인 API에는 댓글에 닿는 기능이 없었다. REST API는 있지만 토큰이 필요했고, 결국 내용을 말로 받아 반영했다.

토큰은 저장소 .env에 있었다. 그걸 알고 나서 API로 읽으니 200이 왔다. 남아 있던 댓글 두 개가 그대로 나왔고, 둘 다 이미 말로 받아 반영이 끝난 것이었다.

여기서 방향이 한 번 꺾였다. 읽을 수 있게 됐으니 “답글을 달까요?”를 물었는데, 되짚어 나온 게 이거였다 — 답글을 달면 화면에 표시가 계속 남아서 뭐가 끝났는지 모른다. 진짜 문제는 읽기가 아니라 화면에서 끝난 것을 가르는 일이었다.

API를 직접 두드려보고 나서 안이 좁혀졌다. 해결 처리가 404라는 걸 확인한 순간 「핀을 없애는 길은 삭제뿐」이 됐고 나머지 안이 자동으로 지워졌다. 추측으로 넘겼으면 안 A를 다 만들고 나서야 안 풀린 걸 알았을 것이다.

그리고 여기서 전제를 잘못 세웠다. 「핀을 없애는 게 목표」라고 놓았다. 그 전제 위에서는 삭제가 유일한 답이라 다른 결론이 나올 수 없었다. 문제를 「어떻게 지울까」로 좁힌 순간 「지워도 되나」를 묻지 않게 됐다.

적용하고 나서 뒤집혔다. 두 건을 실제로 지운 뒤에 나온 지적이 이거였다 — 디자인 요건은 결국 사람이 확인해야 한다. 그 한마디에 전제가 「핀을 없앤다」에서 「사람이 확인한다」로 바뀌었고, 버렸던 두 안의 버린 이유가 동시에 무효가 됐다.

뒤집고 나니 안 A와 안 B가 서로를 메웠다. 안 B는 핀을 열어봐야 하는 게 흠이었고 안 A는 표만 있고 핀이 안 닫히는 게 흠이었는데, 둘을 붙이니 표로 훑고 핀으로 닫는 구조가 됐다. 처음부터 둘을 배타적으로 놓고 본 게 세 번째 실수다.

마지막으로 이력을 디자인 파일 밖으로 뺐다. Figma 안에 프레임으로 만들어 뒀다가, 기록이 답글과 두 곳에 살고 grep에 안 잡힌다는 걸 알고 저장소로 옮겼다.


정리

  • 댓글은 REST API로 읽는다. 플러그인 API에는 댓글에 닿는 기능이 없다
  • 토큰은 .env에 두고 .gitignore에 넣는다. 화면에 찍거나 커밋하지 않는다
  • 반영하면 그 댓글에 답글로 무엇을 고쳤는지 적는다. 「반영했습니다」만 적지 않는다
  • 에이전트는 댓글을 지우지 않는다. 핀을 닫는 것은 사람이다
  • 「반영했다」와 「요청대로 됐다」는 다르다. 디자인에는 그 둘을 갈라줄 테스트가 없다
  • 쌓인 핀은 결함이 아니라 확인이 밀린 만큼이다. 그게 보이는 게 맞다
  • 이력에 요청을 원문 그대로 적는다. 오타도 그대로 옮긴다
  • 이력은 디자인 파일이 아니라 저장소에 둔다. 어긋나고, grep 안 되고, 갈아엎을 때 날아간다
  • 전제를 잘못 세우면 그 위의 논리가 다 맞아도 답이 틀린다. 「어떻게 지울까」로 좁히는 순간 「지워도 되나」를 묻지 않게 됐다

AI 코드 어시스턴트에 바로 적용하기

위 원칙을 규칙 파일 두 벌로 옮겼다. 글은 왜를 담고, 이 둘은 무엇만 담는다.

Claude — .claude/skills/figma-review-comment-workflow/SKILL.md

---
name: figma-review-comment-workflow
description: 디자인 리뷰가 Figma 댓글로 올 때 에이전트가 어디까지 하는지 정한다. 댓글을 REST API로 읽는 법, 반영 후 답글, 댓글을 지우지 않는 이유, 이력을 어디에 어떤 형태로 남기는지를 담는다. Figma 파일의 리뷰를 읽거나 반영할 때, 디자인 요청을 처리할 때 적용한다.
---

# Figma 리뷰 댓글 처리

**에이전트는 댓글을 지우지 않는다. 핀을 닫는 것은 사람이 한다.**

```
1  댓글을 읽는다
2  고친다
3  그 댓글에 답글로 무엇을 고쳤는지 적는다
4  이력에 요청 원문과 반영 내용을 적는다
5  사람이 확인하고 Figma 에서 해결을 누른다   ← 에이전트는 여기 넘지 않는다
```

## 댓글은 REST API 로 읽는다

```bash
set -a; . ./.env; set +a
curl -s -H "X-Figma-Token: $FIGMA_TOKEN" \
  "https://api.figma.com/v1/files/<FILE_KEY>/comments"
```

- **플러그인 API 에는 댓글에 닿는 기능이 없다.** `use_figma` 로는 못 읽는다.
- 토큰은 저장소 루트 `.env``FIGMA_TOKEN` 이다. **`.env` 는 `.gitignore` 에 넣는다.**
- **토큰 값을 화면에 찍지 않고 파일로도 남기지 않는다.** 명령 안에서만 쓴다.

## 반영하면 그 댓글에 답글을 단다

```bash
curl -s -X POST -H "X-Figma-Token: $FIGMA_TOKEN" -H "Content-Type: application/json" \
  -d '{"message":"...","comment_id":"<COMMENT_ID>"}' \
  "https://api.figma.com/v1/files/<FILE_KEY>/comments"
```

- 답글에는 **무엇을 고쳤는지**를 적는다. 「반영했습니다」만 적지 않는다.
- 반응(`/reactions`)은 `:eyes:` 처럼 **콜론 이름**만 받는다. 이모지 문자를 넣으면 400 이다.

## 댓글을 지우지 않는다

- **`DELETE /v1/files/:key/comments/:id` 를 쓰지 않는다.**
- **「반영했다」와 「요청대로 됐다」는 다르다.** 디자인에는 그 둘을 갈라줄 테스트가 없어 판정자가 사람뿐이다.
- 에이전트가 지우면 **요청한 사람이 결과를 보기 전에 확인 단계가 사라진다.**
- **해결 처리는 API 에 없다**`PUT`·`POST /resolve`·`PATCH` 셋 다 404 다. 핀을 닫는 것은 사람만 할 수 있다.
- **쌓인 핀은 결함이 아니라 확인이 밀린 만큼이다.** 그게 보이는 게 맞다.

## 이력은 요청 원문 그대로 적는다

- **요약하지 않는다.** 요약하면 나중에 뜻이 복원되지 않는다. 오타도 그대로 옮긴다.
- **화면은 프레임 이름과 node id 를 같이 적는다.** 이름은 바뀌지만 id 는 안 바뀐다.
- 상태는 셋뿐이다 — `waiting`(답글·확인 대기) · `done`(사람이 해결을 눌렀다) · `deleted`(옛 방식으로 지운 것).

## 이력은 디자인 파일이 아니라 저장소에 둔다

- **디자인 도구 안에 이력 프레임을 만들지 않는다.** 답글과 이력이 두 곳에 살면 한쪽만 고쳤을 때 조용히 어긋난다.
- **디자인 파일은 갈아엎힌다.** 프레임을 지우고 다시 만드는 게 작업이라 기록이 같이 날아간다.
- **캔버스 안 글자는 grep 에 안 잡힌다.** 다음 세션의 에이전트가 못 찾는다.
- 자리는 **데이터 파일과 표시용 페이지를 나눈다.** 항목을 적거나 상태를 바꿀 때는 표시용이 아니라 데이터 파일을 고친다.

## 하지 않는 것

- **댓글을 지우지 않는다.**
- **핀을 대신 닫으려 하지 않는다.** 해결 처리 엔드포인트는 없다.
- **답글만 달고 이력을 안 적지 않는다.** 답글은 핀 안에 있어 훑을 수 없다.
- **요청을 요약해서 이력에 적지 않는다.**
- **디자인 도구 안에 이력을 만들지 않는다.**
- **토큰을 출력하거나 커밋하지 않는다.**

Copilot — .github/instructions/figma-review-comment-workflow.instructions.md

---
description: 디자인 리뷰가 Figma 댓글로 올 때 에이전트가 어디까지 하는가
applyTo: "**"
---

# Figma 리뷰 댓글 처리

- **에이전트는 댓글을 지우지 않는다. 핀을 닫는 것은 사람이 한다.** 순서는 `읽는다 → 고친다 → 그 댓글에 답글을 단다 → 이력에 원문과 반영 내용을 적는다 → 사람이 확인하고 해결을 누른다` 이고, **에이전트는 네 번째까지만 한다.**
- **댓글은 REST API 로 읽는다**`curl -H "X-Figma-Token: $FIGMA_TOKEN" https://api.figma.com/v1/files/<FILE_KEY>/comments`. **플러그인 API 에는 댓글에 닿는 기능이 없다.** 토큰은 저장소 루트 `.env``FIGMA_TOKEN` 이고 `.env``.gitignore` 에 넣는다. **토큰 값을 화면에 찍거나 파일로 남기지 않는다.**
- **반영하면 그 댓글에 답글을 단다**`POST /v1/files/<FILE_KEY>/comments``comment_id` 를 실어 보낸다. 답글에는 **무엇을 고쳤는지**를 적고 「반영했습니다」만 적지 않는다. 반응(`/reactions`)은 `:eyes:` 처럼 **콜론 이름**만 받고 이모지 문자는 400 이다.
- **`DELETE /v1/files/:key/comments/:id` 를 쓰지 않는다.** **「반영했다」와 「요청대로 됐다」는 다르다** — 디자인에는 그 둘을 갈라줄 테스트가 없어 판정자가 사람뿐이다. 에이전트가 지우면 요청한 사람이 결과를 보기 전에 확인 단계가 사라진다.
- **핀을 대신 닫으려 하지 않는다.** 해결 처리는 API 에 없다 — `PUT`·`POST /resolve`·`PATCH` 셋 다 404 다. **쌓인 핀은 결함이 아니라 확인이 밀린 만큼이고, 그게 보이는 게 맞다.**
- **이력에 요청을 원문 그대로 적는다.** 요약하면 나중에 뜻이 복원되지 않으므로 오타도 그대로 옮긴다. 화면은 **프레임 이름과 node id 를 같이** 적는다 — 이름은 바뀌지만 id 는 안 바뀐다. 상태는 `waiting` · `done` · `deleted` 셋뿐이다.
- **이력을 디자인 도구 안에 만들지 않는다.** 답글과 이력이 두 곳에 살면 한쪽만 고쳤을 때 조용히 어긋나고, **디자인 파일은 프레임을 지우고 다시 만드는 게 작업이라 기록이 같이 날아간다.** 캔버스 안 글자는 grep 에도 안 잡힌다. 저장소 안에 두되 **데이터 파일과 표시용 페이지를 나누고, 항목을 적거나 상태를 바꿀 때는 데이터 파일을 고친다.**
- **답글만 달고 이력을 안 적지 않는다.** 답글은 핀 안에 있어서 훑을 수 없다. 이력표는 **핀을 하나씩 열지 않고 무엇부터 볼지 고르는 자리**다.

자신만의 철학을 만들어가는 중입니다.
최상단으로 이동했습니다!
확대 이미지

댓글남기기