2026-10-08

linetta 1.4·1.5 문체 규칙 검사와 앱 안 업데이트 추가

linetta에는 작품마다 문체 노트를 적는 칸이 있다. 에이전트에게 장면을 맡기면 이 노트가 스토리 브리프(에이전트에게 넘기는 작업 설명)에 같이 실려 가지만, 돌아온 장면이 노트대로 쓰였는지 알려면 작가가 처음부터 다시 읽어야 했다. 노트도 자기 문체를 말로 풀어 써야 채워지는 칸이라 대부분 비어 있었다.

그래서 10월 6일에 낸 v1.4.0에서 이 두 군데를 손봤다.

피할 표현과 문장 길이만 검사하기

규칙은 문체 노트에서 뽑지 않고 따로 적는다. 피할 표현은 한 줄에 하나씩(최대 100개, 하나에 80자까지), 문장 길이 상한은 글자 수로 적는다. 한도를 넘긴 목록은 앞부분만 잘라 저장하지 않고 저장 자체를 거절해서, 작가가 적은 것보다 짧은 목록으로 검사하는 일이 없게 했다.

검사에는 모델이 끼지 않는다. 같은 원고에 같은 규칙이면 결과도 같고, 원고는 손대지 않는다. 세계관 패널의 문체 규칙과 검사 섹션에서 “이 장면 검사”나 “작품 전체 검사”를 누르면 위반 목록이 뜨고, 한 줄을 누르면 그 장면이 열린다. 에이전트 쪽에서는 MCP 읽기 툴 linetta_analyze_style이 같은 검사를 부른다.

결과가 어떻게 생겼는지는 직접 돌려 보는 게 빠르다. 아래 샘플 장면을 이 글을 쓰면서 따로 지어서 linetta 저장소의 검사 함수 style.Check에 넣어 봤다. 규칙은 피할 표현 “왠지 모르게”와 “그녀는”, 문장 길이 상한 60자로 정했다.

문이 열리자 서늘한 바람이 들어왔다. 윤서는 어깨를 움츠렸다.

그녀는 왠지 모르게 이 집이 낯설지 않았고, 복도 끝에 걸린 액자와 계단 난간의 긁힌 자국과 부엌에서 새어 나오는 희미한 커피 냄새까지 어디선가 본 듯한 기분이 들어 한참을 현관에 서 있었다.

"누구 있어요?" 대답은 없었다. 왠지 모르게 등 뒤가 서늘했다.

나온 결과다. 블록이 길어서 네 번째 위반은 줄였다.

{
  "scenes_checked": 1,
  "total": 4,
  "violations": [
    {
      "node_id": "sample",
      "label": "3화",
      "rule": "avoid_phrase",
      "paragraph": 2,
      "phrase": "그녀는",
      "excerpt": "그녀는 왠지 모르게 이 집이 낯설지 않았고…"
    },
    {
      "node_id": "sample",
      "label": "3화",
      "rule": "avoid_phrase",
      "paragraph": 2,
      "phrase": "왠지 모르게",
      "excerpt": "그녀는 왠지 모르게 이 집이 낯설지 않았고, 복도 끝에…"
    },
    {
      "node_id": "sample",
      "label": "3화",
      "rule": "sentence_too_long",
      "paragraph": 2,
      "excerpt": "그녀는 왠지 모르게 이 집이 낯설지 않았고, 복도 끝에 걸린 액자와 계단 난간의 긁힌 자국과 부엌에서 새어 …",
      "length": 107,
      "limit": 60
    },
    …
  ],
  "truncated": false
}

두 번째 문단의 한 문장에서 세 건이 걸렸다. 피할 표현 두 개가 들어 있고, 길이도 107자라 상한을 넘는다. 줄인 네 번째는 셋째 문단의 “왠지 모르게”다. 규칙에는 “왠지 모르게”를 먼저 적었는데 결과에는 “그녀는”이 먼저 나온다. 원고에 나온 순서대로 줄을 세우기 때문이다. 대소문자는 무시하지만 띄어쓰기는 무시하지 않는다. “왠지모르게”처럼 붙여 쓴 곳까지 잡으려면 그 형태도 목록에 적어야 한다.

규칙을 하나도 적지 않은 작품이면 linetta_analyze_style이 빈 rules를 같이 돌려준다. 에이전트가 이걸 보고 “검사할 규칙이 없음”과 “위반 없음”을 구분한다.

검사가 제대로 도는지는 #166에 넣은 테스트로 확인한다. 실제 MCP 서버를 띄워서 피할 표현을 넣은 장면에서는 장면·문단·표현을 정확히 짚는지, 규칙을 지킨 장면에서는 위반이 하나도 안 나오는지, 검사 전후로 장면 본문이 그대로인지를 본다.

세계관 패널에서 문체 규칙을 적고 장면을 검사한 화면 화면은 다른 샘플로 찍었다. 피할 표현 세 개와 문장 길이 상한 20자를 적었더니 10곳이 걸렸다.

어조와 리듬은 검사 엔진이 보지 않고, 시점과 시제도 기계로 판정할 방법이 없어서 뺐다. 이런 건 에이전트가 문체 노트를 읽고 판단하되, 고치지는 말고 보고만 하라고 툴 설명과 내장 에이전트 프롬프트에 적어 뒀다.

원고에서 문체 프로필 초안 뽑기

비어 있는 문체 노트는 이미 쓴 원고로 채운다. 문장 길이의 평균·중앙값·90분위·최대, 문단당 문장 수, 대화 비율, 자주 쓰는 종결 표현 상위 여덟 개처럼 셀 수 있는 건 엔진이 세고, 이 숫자들이 linetta_analyze_style 결과에 stats로 붙는다. 에이전트는 숫자와 원고를 같이 보고 서술형 초안을 써서 linetta_propose_style_profile로 올린다.

올라온 초안은 대기 상태로만 저장되고, 승인 전에는 스토리 브리프에 들어가지 않는다. 화면에 “초안 대기” 배지가 뜨면 작가가 초안을 고친 뒤 문체 노트 뒤에 덧붙이기, 노트를 이걸로 바꾸기, 버리기 중 하나를 고른다. 승인 버튼은 앱에만 있고, MCP에는 승인 툴이 없다.

지금까지 앱에 없던 문체 노트 편집 화면도 같은 섹션에 넣었다.

v1.4.0에는 이것 말고도 몇 가지가 같이 들어갔다. 지난 글에서 다음 릴리스로 미뤄 둔 인물 비주얼 시트 쓰기 툴 네 개, Markdown 내보내기가 목록·코드 블록·링크 서식을 버리던 버그 수정, 그리고 같은 변환기를 써서 linetta_read_scene이 장면을 Markdown으로도 돌려주게 한 변경이다.

메뉴에서 업데이트 확인

v1.5.0은 같은 날 저녁에 냈다. 트레이 메뉴와 macOS 앱 메뉴에 업데이트 확인… 항목이 생겼다. 새 버전이 있으면 내려받을지 먼저 묻고, 다 받은 뒤 설치하고 다시 시작할지 한 번 더 묻는다. 받는 동안에도 계속 쓰고 있을 수 있어서 질문을 둘로 나눴다. 설치는 서명이 공개키와 맞는 설치본만 한다.

macOS 앱 메뉴에 새로 생긴 업데이트 확인… 항목

앱을 켜고 30초 뒤에는 알아서 한 번 확인한다. 같은 릴리스는 한 번만 알리고, 창이 트레이에 숨어 있으면 대화상자를 띄우지 않는다.

자체 업데이트가 되는 건 macOS 직접 배포(Homebrew 포함), Windows 설치본, Linux AppImage·deb·rpm이다. Mac App Store 빌드는 스토어가 업데이트를 맡으니 이 기능을 빼고 빌드한다. 끝까지 돌려 본 건 macOS 로컬 빌드 하나로, 내려받기, 서명 검증, 앱 교체, 재시작까지 확인했다. Windows와 Linux의 설치 단계는 이번 릴리스에서 처음 돌고, 공증을 거친 macOS 배포본이 업데이트 파일에 그대로 담기는지도 아직 확인하지 않았다.

1.4.0 이하에는 업데이터가 없어서 1.5.0으로 올리는 한 번만은 손으로 해야 한다. Homebrew로 설치했다면 brew upgrade --cask linetta로 올리고, Windows와 Linux, Homebrew 없이 설치한 macOS는 GitHub 릴리스에서 새 설치본을 받으면 된다. App Store 빌드는 원래 스토어가 업데이트한다.

이번 글에 나온 PR

  • 문체 규칙과 결정적 검사: #166
  • 문체 프로필 초안: #167
  • 인물 비주얼 시트 쓰기 툴: #158
  • Markdown 내보내기 수정과 장면 Markdown 읽기: #164, #165
  • 앱 안 업데이트: #170

같은 작업대에서 나온 이웃 도구입니다.