하루스페이스 랩
자유로운 대화가 코드가 되는 순간, 어디에 문을 둘 것인가
프로젝트 조율 대화와 실제 코드 작업을 연결하면서 편집 가능한 초안, 공통 작업 액션, 단계별 거부·재작업과 감사 경계를 만든 여드레의 기록입니다.

Summary
한눈에 보기
- 조율 대화는 읽기 전용으로 유지하고 사람이 편집·확인한 실행 초안만 기존 코드 작업 승인 흐름으로 전달했습니다.
- 질문·답변은 전용 원장에 한 번만 저장하고 작업방에는 승인된 초안과 참조만 남겼습니다.
- 채팅과 조율 화면의 작업 보기·승인·거부·재작업 조건을 공통화하고 과거 거부 이력을 보존했습니다.
이 글은 2026년 8월 17–24일의 설계 문서, Git 기록과 운영 이슈를 바탕으로 다시 쓴 Haru Space 개발 회고다. 실제 프로젝트 대화와 거부 사유, 그룹·방·작업 식별자, 내부 주소와 인증 정보는 공개하지 않는다.
프로젝트는 코드보다 대화에서 먼저 만들어진다.
무엇을 만들지, 누구를 위한 것인지, 이번 범위에서 무엇을 하지 않을지, 어떤 결과를 완료로 볼지 여러 번 이야기한 뒤에야 실제 작업이 선명해진다. Haru Space의 작업방은 실행과 승인에는 강했지만, 이런 긴 조율을 하기에는 단계 카드가 너무 앞에 나왔다.
그렇다고 일반 채팅의 모든 대화를 코드 작업으로 이어 붙일 수는 없었다. 사람은 아이디어를 탐색하고 있을 뿐인데 AI가 파일 변경 의도로 해석할 수 있기 때문이다.
우리는 프로젝트 조율이라는 별도 화면을 만들었다. 그리고 가장 많은 시간을 쓴 것은 대화를 잘 요약하는 일이 아니라, 요약이 실제 코드가 되는 순간의 경계를 정하는 일이었다.
자유로운 대화는 자유롭게 남아야 했다. 코드가 되는 순간에는 대상, 문장, 권한과 책임을 사람이 다시 확인해야 했다.
조율은 읽기 전용으로 시작했다
프로젝트 조율에서 그룹관리자는 작업공간과 AI 펫을 고르고 목표, 현재 코드, 위험과 완료 기준을 계속 논의할 수 있었다. AI는 연결된 저장소를 읽고 설명할 수 있지만 파일을 수정하거나 커밋·푸시·배포할 수 없었다.
이 경계는 UI 문구가 아니라 실행 계약으로 분리했다. 조율 대화는 읽기 전용 프로필과 전용 문맥을 사용했다. 실제 쓰기 작업은 별도의 기존 편집 프로필과 격리 작업공간에서 시작했다. 대화가 길어졌다고 낮은 권한의 문맥이 자연스럽게 쓰기 권한을 얻지 않게 했다.
접근 권한도 플랫폼 역할이 아닌 현재 그룹 멤버십으로 확인했다. 최고관리자라도 그 그룹의 실제 관리자가 아니면 비공개 조율에 들어올 수 없었다. 작업공간과 펫도 현재 그룹에 속하고 사용자가 접근할 수 있는 대상만 선택할 수 있었다.
프로젝트에 대해 많이 안다는 사실과 그 프로젝트를 바꿀 권한은 별개였다.
초안 만들기에도 한 번의 멈춤을 두었다
조율이 충분히 진행되면 AI가 실행 가능한 작업 초안을 만들었다. 초기 버튼은 누르는 즉시 모델을 호출했다. 잘못 눌러도 토큰과 대기 시간이 발생했고, 사용자는 그 동작이 파일 수정까지 시작하는지 알기 어려웠다.
초안 생성 전 확인 단계를 추가했다. 이 동작은 대화를 정리할 뿐 코드를 바꾸지 않는다고 설명했다. 초안의 길이와 항목 수도 제한하고, 이미 전용 대화 문맥에 있는 작업방 메시지를 다시 크게 첨부하지 않았다.
AI가 쓴 초안은 읽기 전용 결과로 고정하지 않았다. 관리자가 텍스트를 직접 고칠 수 있게 했다. AI 원문과 글자 하나까지 같아야 한다고 요구하는 대신, 출처가 이 그룹의 성공한 조율 초안인지, 아직 다른 작업으로 전달되지 않았는지, 최종 문장이 비어 있지 않고 실행 가능한 목표인지 서버가 확인했다.
사람은 단순 승인자가 아니라 실제 작업 요청의 편집자였다.
“실행하지 말라”는 문장이 실제 실행으로 전달됐다
초안 흐름의 가장 상징적인 실패는 프롬프트 안의 메타 지시에서 나왔다.
AI에게 초안을 만들 때 “지금은 파일 수정이나 배포를 실행하지 말라”고 안내했다. 의도는 초안 작성 단계에서만 행동하지 말라는 것이었다. 하지만 한 초안은 그 문장을 최종 작업의 제외 범위에 그대로 넣었다. 이후 초안은 실제 편집 작업으로 전달됐다.
Codex는 지시를 정확히 따랐다. 코드를 살펴보고 빌드 상태를 확인했지만 파일을 바꾸지 않았다. 실행기는 변경이 있어야 하는 작업이 무변경으로 끝났기 때문에 실패로 처리했다.
AI가 잘못 알아들었다고만 할 수 없는 사건이었다. 서로 다른 단계의 지시를 한 문서에 섞어 보낸 시스템 책임이 더 컸다.
세 언어의 초안 프롬프트에서 작성 단계의 금지 문구를 최종 초안에 옮기지 않도록 고쳤다. 더 중요한 보완은 서버 검증이었다. 실제 편집 작업과 상충하는 코드·파일 변경 금지 문구가 있으면 전달 전에 막고, 사용자가 초안을 고치게 했다.
프롬프트를 잘 쓰는 것과 실행 계약을 검증하는 것은 서로 대체할 수 없었다.
질문과 답변을 작업방에 복사하지 않았다
프로젝트 조율의 첫 버전은 AI 응답을 임시 화면 상태로 만들고 일부 결과를 일반 작업방에 투영했다. 화면을 나갔다 돌아오면 질문은 사라지고 답변만 작업방에 남았다. 대화 흐름은 끊겼고, 읽기 전용 조율 작업과 실제 개발 작업도 같은 목록에 섞였다.
전체 대화를 작업방과 작업 요청에 모두 복사하면 데이터와 모델 문맥이 계속 커진다. 반대로 아무것도 저장하지 않으면 합의의 근거를 잃는다.
우리는 조율 대화 원장을 따로 두었다.
- 질문과 AI 답변은 조율 원장에 한 번만 저장한다.
- 일반 작업방에는 원문을 복사하지 않는다.
- 사람이 승인한 최종 초안만 실제 작업의 실행 스냅샷으로 남긴다.
- 작업방에는 승인 초안과 원본 조율로 돌아가는 참조를 표시한다.
- 오래된 대화는 사용자가 요청할 때 페이지 단위로 가져온다.
- 모델에는 최근의 제한된 메시지만 전달하고 일정 턴 뒤 새 문맥으로 교체한다.
기록을 남긴다는 말이 모든 중복 사본을 남긴다는 뜻은 아니었다. 원본은 한 곳에 두고, 실행에는 사람이 확인한 최소 스냅샷을 사용했다.
같은 작업인데 화면마다 버튼이 달랐다
실제 작업이 생성된 뒤에는 또 다른 불일치가 나타났다. 작업 채팅방에서는 작업 보기, 수정 승인·거부, 의존성 승인, 커밋·푸시 요청과 PR 결정 버튼을 사용할 수 있었다. 조율 화면의 초안 카드에는 상태 문구만 보였다.
같은 작업인데 어디에서 보느냐에 따라 할 수 있는 행동이 달라 보였다. 더 위험한 것은 각 화면이 버튼 조건을 따로 구현하면서 실패한 작업에도 커밋·푸시 요청이 나타나거나, 거부된 PR에서 작업 보기 자체가 사라지는 일이었다.
우리는 공통 작업 정책과 액션 컴포넌트로 합쳤다.
작업 보기는 새 기능도, 이어하기 버튼도 아니었다. 같은 작업 ID로 기존 작업실 팝업을 여는 동작이었다. 진행, 성공, 실패, 거부와 PR 상태에 관계없이 유효한 작업이면 상세, 변경 파일과 감사 이력을 다시 볼 수 있게 했다.
반면 실행 버튼은 엄격하게 현재 단계만 따랐다.
- 수정·의존성·저장소 반영과 PR 중 지금 결정할 단계만 표시한다.
- 실제 편집이 성공하고 변경 파일과 결과 지문이 있을 때만 최초 커밋·푸시 요청을 보여 준다.
- 실패, 취소, 거부, 분석 작업과 변경 없는 성공에는 저장소 반영을 제안하지 않는다.
- PR 결정은 현재 보고 있는 방이 아니라 서버에 기록된 승인방을 기준으로 다시 검증한다.
상세를 볼 권리와 새로운 변경을 실행할 권리를 분리한 것이다.
거부는 네 가지 다른 시작점을 가졌다
“거부 사유를 반영해 다시 작업”도 한 종류가 아니었다. 무엇을 거부했는지에 따라 안전한 시작점이 달랐다.
코드 실행 전 거부
아직 변경물이 없으므로 현재 권위 저장소에서 새 격리 작업을 시작한다. 과거 작업공간을 이어받을 이유가 없다.
의존성 승인 거부
승인 전까지 만든 안전한 변경과 작업 문맥이 남아 있을 수 있다. 서버와 브리지가 원 작업을 검증한 경우에만 그 격리 작업공간에서 별도의 후속 작업을 시작한다.
저장소 반영 승인 거부
파일 수정과 검증은 끝났지만 저장소에 반영하지 않기로 한 결정이다. 검증된 격리 변경을 출발점으로 삼되 새 작업이 승인 절차를 처음부터 다시 거친다.
PR 병합 거부
원격 소스 브랜치에 이미 검토 대상이 있다. 그 브랜치에서 새 격리 작업을 시작하고 원래 보호 브랜치를 최종 대상으로 유지한다. 거부된 PR을 몰래 고치거나 과거 결정을 성공으로 바꾸지 않는다.
전달 실행기의 기술적 실패는 사람 거부와도 달랐다. 이미 승인된 변경 지문이 있고 실행만 실패했다면 자식 재작업을 만들지 않고 같은 전달을 재시도한다. 검증된 커밋이 있으면 불필요하게 다시 커밋하지 않고 푸시 단계부터 복구한다.
UI에서 모두 “다시”라고 보일 수 있지만, 감사와 변경 원본은 전혀 달랐다.
거부 사유는 다음 작업의 입력이자 보호 데이터였다
모든 거부에는 짧은 사유를 필수로 했다. 빈 값과 지나치게 긴 입력, 제어 문자는 클라이언트와 서버에서 함께 막았다. 사유는 작업 상세와 필요한 후속 프롬프트에서만 사용하고 일반 감사 상세와 로그에 반복 복사하지 않았다.
원 작업의 상태, 결정자, 시각과 사유는 변경하지 않았다. 후속 작업은 별도 식별자와 새 변경 지문, 새 승인 이력을 가졌다. 과거 거부가 사라지지 않아야 “왜 다시 만들었는가”를 설명할 수 있었다.
사용자가 사유에 민감 정보를 넣을 가능성도 있었다. 기존 중앙 마스킹을 적용하되, 필터가 있다고 원문을 여러 곳에 보관하지는 않았다. 필요한 곳을 줄이는 것이 첫 방어였다.
긴 보안 표 하나가 채팅 영역을 밀어냈다
프로젝트 조율에는 코드, URL과 보안 감사 표처럼 긴 텍스트가 자주 들어왔다. 한 대화에서는 공백 없이 이어진 ASCII 표가 메시지의 최소 폭을 키웠다. 화면은 가로 넘침을 숨겨 오른쪽 내용이 잘리고 채팅 전체가 한쪽으로 밀린 것처럼 보였다.
본문에 줄바꿈 규칙만 넣어서는 충분하지 않았다. 최상위 화면부터 채팅 패널, 스크롤 영역, 대화 행과 말풍선까지 모든 grid·flex 계층이 자식 폭을 줄일 수 있어야 했다. 사용자 말풍선은 내용 폭을 쓰되 채팅 열의 일정 범위를 넘지 않게 하고, 코드와 표만 메시지 내부에서 가로 스크롤하도록 했다.
이 레이아웃 이슈도 제품 경계와 닿아 있었다. 중요한 거부 사유나 감사 결과가 화면 밖에 잘리면 사용자는 승인 결정을 제대로 할 수 없다. 읽을 수 있는 UI는 승인 체계의 일부였다.
대화를 코드로 바꾸는 체크리스트
이 흐름을 다시 만든다면 다음을 먼저 확인할 것이다.
1. 대화 실행기는 끝까지 읽기 전용인가
많이 논의했다는 이유로 쓰기 권한을 얻지 않는다. 실제 작업은 새 계약으로 시작한다.
2. 사람은 AI 초안을 직접 고칠 수 있는가
AI 결과를 승인·거부만 하는 대신 최종 작업 문장을 사람이 책임지고 편집한다.
3. 초안의 출처와 실행 가능성을 따로 검증하는가
올바른 조율 메시지인지 확인하고, 실제 편집 목표와 모순되는 문구도 서버에서 막는다.
4. 원본 대화와 실행 스냅샷을 중복 저장하지 않는가
조율 원장은 한 번만 보관하고 작업에는 승인된 최소 초안과 참조를 남긴다.
5. 모든 화면이 같은 작업 정책을 사용하는가
작업 보기와 현재 단계의 액션 조건을 공통화한다. 화면별 편의 조건이 서버 권한보다 앞서지 않게 한다.
6. 거부 단계마다 올바른 원본에서 다시 시작하는가
변경 전에는 새 기준, 변경 후에는 검증된 작업공간, PR 후에는 소스 브랜치를 사용한다. 기술 실패는 같은 전달을 복구한다.
7. 과거 결정을 지우지 않는가
후속 작업은 새 이력으로 만든다. 거부 사유는 필요한 범위에서 이어 가되 원 작업을 성공으로 덮지 않는다.
자유롭게 말하고 신중하게 실행하는 공간
프로젝트 조율을 만든 이유는 AI에게 더 빨리 코드를 맡기기 위해서가 아니었다. 아직 결정되지 않은 생각을 안전하게 오래 다루고, 충분히 선명해진 순간에만 기존 작업 체계로 넘기기 위해서였다.
여드레 동안 초안 버튼에 확인창이 생겼고, AI 원고는 편집 가능해졌으며, 조율 원장과 작업방이 분리됐다. 실패·거부된 작업에서도 상세를 볼 수 있게 했고, 실제 변경이 있는 성공 작업에만 저장소 반영을 제안했다. 재작업은 거부 단계에 맞는 원본에서 새 이력으로 시작했다.
이 모든 변화의 중심에는 같은 생각이 있었다.
좋은 AI 협업은 대화를 곧바로 실행하는 능력이 아니라, 자유로운 말이 책임 있는 변경으로 바뀌는 정확한 순간을 사람이 선택하게 하는 능력이었다.
반응을 남기면 중복 방지를 위한 무작위 식별자가 이 브라우저에 저장될 수 있습니다.

