~11 min · terminal-profile, coding-agents, safety, bracketed-paste
Level 0불씨 없음
0 XP0/48 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"텍스트 필드에선 잘못된 붙여넣기가 창피해. 터미널에선 잘못된 붙여넣기가 실행돼."
왜 터미널이 특별한가
Terminal, iTerm, VS Code 나 Cursor 안의 터미널, 아니면 Codex 나 Claude Code 같은 코딩 에이전트 CLI 에 받아쓰는 건 일급 사용 사례야. 아빠는 하루 종일 거기서 사니까. 그런데 터미널은 범용 텍스트 필드가 아니야. 거기 붙여넣은 텍스트는 실행될 수 있어. 돌기 전에 읽을 수도 없는 큰 붙여넣기 블록은 잘해야 사람을 방해하고, 못하면 위험해. 그래서 Firekeeper 는 터미널한테 Mail 작성 창이랑은 다른 규칙의 삽입 프로파일을 따로 줘.
터미널 프로파일 규칙
번들 id 로 타깃이 터미널인지 알아내. Terminal, iTerm2, Ghostty, 에디터 안에 붙은 터미널, 에이전트 CLI 까지. 그리고 동작을 바꿔.
짧은 한 줄짜리 받아쓰기. 평범하게 붙여넣어.
길거나 여러 줄짜리 받아쓰기. 보이고 손댈 수 있게 유지해. 명시적으로 '터미널로 보내기' 를 누르는 프리뷰 오버레이를 띄우거나, 천천히 줄 단위로 넣거나, 타깃이 지원하면 bracketed paste 를 인식해서 넣거나.
긴 터미널 받아쓰기 뒤에 Enter 를 절대 자동으로 안 눌러. 유저가 명시적으로 '엔터 쳐' 라고 말하고 거기에 그 동작을 켜 뒀을 때만 눌러.
여기서 전부를 떠받치는 건 Enter 규칙이야. 자동으로 실행되는 받아쓰기는 곧 생각이 덜 끝난 명령도 돌려 버릴 수 있는 받아쓰기니까.
범용 텍스트 필드: 텍스트 붙여넣기 -> 완료
터미널 프로파일: 터미널 감지
-> 짧아? 붙여넣기
-> 길어? 프리뷰 / 청크 / bracketed-paste, 편집 가능 유지
-> 말한 '엔터 쳐' 그리고 켜졌을 때만 Enter
작업 루프 존중
더 깊은 생각은 유저가 실제로 일하는 흐름을 존중하는 거야. 코딩 에이전트한테 긴 프롬프트를 받아쓰는 개발자는 보내기 전에 보고 고치고 싶어 해. 도구가 그 흐름이랑 싸우지 않고 맞춰 준다는 게 그런 거고. Wispr Flow 도 이걸 알아냈어. Firekeeper 는 여기서 한 발 더 가서, 있으면 좋은 기능이 아니라 설계 요구사항으로 다뤄. 터미널 프로파일이 '받아쓸 수 있어' 를 '내가 실제로 개발하는 환경에 안전하게 받아쓸 수 있어' 로 바꿔 주는 거지.
앱이 자기 판단으로 터미널에 Enter 를 합성하는 일은 절대 없어야 해. 터미널 받아쓰기 뒤에 Enter 를 자동으로 누르면 반쯤 만든 명령이 돌아갈 수 있어. 합성된 Enter 로 가는 길은 하나뿐이야. 유저가 설정을 켜 둔 채로 '엔터 쳐' 라고 명시적으로 말하는 것. 의도적인 신호 두 개고, 추론은 절대 아니고. 애매하면 커서를 텍스트 끝에 두고 사람이 누르게 둬.
번들 id 로 타깃 종류를 알아내고, 그다음에 특화해. 최전면 앱의 번들 식별자는 삽입 프로파일을 고르는 데 쓸 수 있는 안정적이고 싼 신호야. 알려진 터미널이랑 코딩 에이전트 번들 id 목록을 유지하다가, 타깃이 거기 걸리면 조심스러운 프로파일로 바꿔. 모르는 앱은 터미널 프로파일이 아니라 안전한 범용 경로를 받고.
Code
실제로 들어간 것: 터미널 목록과 Enter 가드 (FirekeeperKit + DictationController)·swift
// FirekeeperKit AppCategory.classify(bundleID:) — 터미널 목록
private static let terminalIDs: Set<String> = [
"com.apple.terminal", "com.googlecode.iterm2", "dev.warp.warp-stable", "dev.warp.warp",
"com.mitchellh.ghostty", "com.github.wez.wezterm", "net.kovidgoyal.kitty", "co.zeit.hyper",
"com.cwk.smolder", // 가족 터미널, 2026-09-27 리뷰 전까지 빠져 있었음
]
// VS Code, Cursor, Xcode, Obsidian 은 .editor: 통합 터미널은 그 에디터의 id 를 보고해.
// DictationController — 가드가 켜져 있으면(기본값) 터미널에선 Enter 를 붙들어 둬.
var pressEnter = EnterCommand.detect(in: raw) || EnterCommand.detect(in: output.text)
let text = EnterCommand.strip(from: output.text)
if pressEnter, settings.terminalGuardEnabled, snapshot?.category == .terminal {
// 터미널은 Enter 에 실행돼; 셸에서 잘못 들은 "엔터 쳐" 는 살아 있는 명령이야.
pressEnter = false
guardNote = " (terminal guard: Enter suppressed)"
}
텍스트를 넣었을 때 평범한 텍스트 필드랑 결과가 달라지는 타깃 셋을 적어봐. 터미널, 스프레드시트 수식 입력줄, Enter 로 보내는 채팅 입력 같은 거. 각각에 대해 위험한 기본 동작이 뭔지, 그리고 거기 받아쓰기를 안전하게 하려면 어떤 특화 규칙을 더할지 써봐.
Hint
패턴은 같아. 그 타깃이 텍스트를 담는 것 말고 뭘 더 하는지 찾아내는 거야. 실행하거나(터미널), 계산하거나(수식 입력줄), 보내거나(Enter 로 전송되는 채팅). 특화 규칙은 늘 제일 되돌릴 수 없는 결과를 묶어. 자동 실행 금지, 자동 계산 금지, 자동 전송 금지. 타깃 종류를 알아내고, 위험한 마지막 단계는 사람이 할 때까지 붙들어 둬.
Progress
Progress is local-only — sign in to sync across devices.