← Docs hub

PUI Launcher 화자 등록 Overlay 연동 구현 설계

이 문서는 SKMLauncher2의 setLauncherScreen과 VitalSign PUI 진입 구조를 실제 코드로 추적하고, ondevice 앱의 기존 화자 관리·등록 화면을 PUI 버튼과 DeviceAgent 이벤트에서 안전하게 여는 구현안을 정리한다.

현재 상태: 이 페이지는 구현 전 설계 기준선이다. 기존 ondevice overlay와 등록 엔진은 코드에 존재하지만, Launcher용 Receiver·service action·결과 callback은 아직 구현하지 않았다. UI 가이드가 제공되면 4장의 교체 가능 영역을 확정한 뒤 이 계약을 기준으로 구현한다.

핵심 결론은 다음과 같다.

버전 주의: 분석한 MR6 SKMLauncher2 소스는 0.277, 연결 기기 192.168.123.118:5555의 설치본은 0.285다. 구조적 결론은 유효하지만 실제 반영 전 0.285 소스에서 동일 callback과 화면 정책을 대조해야 한다.

현재 VitalSign 및 ondevice 화자 등록 진입 흐름

1. 현재 구현에서 확인된 사실

1.1 PUI VitalSign 버튼

apps/SKMLauncher2/.../ui/stay/StayActivity.java:92-98

binding.btnVitalSign.setOnClickListener(
    __ -> ((SKMLauncherApp) getApplication()).launchVitalSignApp("PUI")
);

PUI 버튼은 런처 화면을 교체하지 않고 SKMLauncherApp의 공통 실행 함수로 넘긴다.

1.2 DeviceAgent setLauncherScreen

apps/SKMLauncher2/.../ui/SKMLauncherApp.java:1428-1436

method == setLauncherScreen
  -> outdata.screenName
  -> LauncherScreen.fromScreenName()
  -> launchScreenByLlm()

LauncherScreen.java에는 VITAL_SIGN("vitalSign")이 있고, launchScreenByLlm()VITAL_SIGN 분기는 launchVitalSignApp("LLM")을 호출한다.

따라서 진입 주체만 다를 뿐 다음 두 경로는 같은 함수로 수렴한다.

PUI button -> launchVitalSignApp("PUI")
LLM callback -> setLauncherScreen(vitalSign) -> launchVitalSignApp("LLM")

1.3 VitalSign은 별도 앱

SKMLauncherApp.java:2072-2095는 다음을 수행한다.

  1. Privacy mode를 확인한다.
  2. com.gbsoft.vitalsign 설치 여부를 확인한다.
  3. 현재 공기청정, interaction schedule, 이동을 정지한다.
  4. getLaunchIntentForPackage("com.gbsoft.vitalsign")를 얻는다.
  5. START_VITAL_SIGN_BY=PUI|LLM extra를 넣고 Activity를 실행한다.

연결 기기에서도 다음이 확인됐다.

설치 위치 버전
SKMLauncher /system/priv-app/SKMLauncher/SKMLauncher.apk 0.285
VitalSign /system/priv-app/VitalSign/VitalSign.apk 1.6.7
ondevice /system/priv-app/MaumAi/MaumAi.apk 1.19.36

VitalSign main component는 com.gbsoft.vitalsign/.MainActivity다.

1.4 ondevice에는 등록 화면이 이미 있다

ForegroundService.kt의 현재 구현:

코드 역할
isSpeakerRegisterCommand() STT 결과에 화자인식 포함 여부 확인
showSpeakerManageOverlay() 등록, 목록, 뒤로가기 관리 화면 표시
showSpeakerRegisterOverlay() 이름 입력, 녹음, 초기화, 전체 등록 화면 표시
startSpeakerEnrollment() 기존 STT 녹음 정지 후 등록용 AudioRecord 획득
stopSpeakerEnrollment() WAV 저장과 embedding 등록 후 STT 복구
SpeakerListActivity 등록 화자 목록
SpeakerHistoryActivity 화자별 기록

등록 중 마이크 소유권도 이미 처리한다.

resumeSttAfterEnrollment = AudioRecordManager.isRecording()
-> stopContinuousRecording()
-> requestAudioRecord(speakerEnrollmentClientId)
-> 등록 녹음
-> stopSpeakerEnrollment()
-> restoreSttAfterEnrollment()

즉 새로 만들어야 할 핵심은 등록 UI 자체가 아니라 외부에서 내부 UI를 열 수 있는 계약이다.

1.5 지금 바로 직접 실행할 수 없는 이유

ondevice manifest에서 다음 컴포넌트는 모두 exported=false다.

이는 외부 앱이 임의로 진입하지 못하게 하는 올바른 기본값이다. 런처에서 현재 Activity 이름을 직접 start하거나 service component를 호출하는 방식으로 풀면 권한과 수명주기 계약이 무너진다.

2. 권장 목표 구조

권장 PUI 화자 등록 연동 구조

2.1 책임 배치

영역 책임
PUI / SKMLauncher2 버튼, setLauncherScreen screen name, 현재 화면·도메인 정책, 진입 요청
앱 간 entrypoint 호출자 제한, explicit intent, 중복 요청과 초기화 상태 검증
ondevice ForegroundService 기존 overlay 표시, 마이크 전환, embedding 등록
DeviceAgent / TaskManager LLM 경로가 필요할 때 queue, timeout, terminal status

2.2 ondevice 변경

  1. com.skmagic.ondeviceai.permission.SPEAKER_ENROLLMENTprotectionLevel=signature로 선언한다.
  2. 이 권한으로 보호된 SpeakerEnrollmentReceiver를 만든다.
  3. 런처는 package가 아니라 Receiver component까지 지정한 explicit intent를 보낸다.
  4. Receiver는 기존 ForegroundServiceACTION_SHOW_SPEAKER_MANAGE를 전달한다.
  5. 서비스는 main thread에서 기존 showSpeakerManageOverlay()를 호출한다.
  6. overlay 추가 성공, 이미 표시 중, 권한 없음, 서비스 미초기화를 각각 구분해 로그와 결과로 남긴다.

권장 action 예시:

com.skmagic.ondeviceai.action.SHOW_SPEAKER_MANAGE
com.skmagic.ondeviceai.action.SHOW_SPEAKER_REGISTER

현재 코드를 그대로 재사용하는 기준안은 관리 화면부터 여는 것이다. 등록, 목록, 뒤로가기의 현재 UX를 유지할 수 있고 향후 삭제·동의 화면도 같은 entrypoint 아래 확장할 수 있다. 다만 PUI가 곧바로 “등록 씬”을 요구하면 targetScreen=REGISTER로 직접 등록 overlay를 열 수 있다. 최종 기본값은 UI 가이드에서 결정하고 IPC 계약은 두 진입을 모두 지원한다.

2.3 SKMLauncher2 변경

LauncherScreen에 다음 값을 추가한다.

SPEAKER_REGISTRATION("speakerRegistration")

PUI 버튼과 LLM 경로는 반드시 같은 함수로 수렴시킨다.

PUI button
  -> launchSpeakerEnrollment("PUI")

setLauncherScreen(speakerRegistration)
  -> launchScreenByLlm()
  -> launchSpeakerEnrollment("LLM")

launchSpeakerEnrollment()은 다음을 책임진다.

2.4 완료 시점

현재 launchScreenByLlm()은 switch 실행 직후 reportScreenApplied(appliedScreenName)를 호출한다. 외부 앱/overlay 연동에서는 intent 전송 성공이 화면 표시 성공과 같지 않다.

따라서 speakerRegistration은 다음 중 하나로 완료를 닫아야 한다.

REQUEST_ACCEPTED != SCREEN_APPLIED != ENROLLMENT_COMPLETED

제품 정책상 어떤 상태를 setLauncherScreenStatus=success로 볼지 먼저 정해야 잘못된 조기 완료를 막을 수 있다. 화면 전환 task라면 SCREEN_APPLIED, 등록 workflow라면 ENROLLMENT_COMPLETED가 terminal 기준이다.

3. 상세 구현 계약

3.1 런타임 시퀀스

PUI 화자 등록 요청·표시·종료 시퀀스

시퀀스 SVG 원본 크게 보기

외부 진입에서는 다음 경계를 지킨다.

  1. Launcher는 requestId를 생성하고 explicit broadcast를 보낸다.
  2. SpeakerEnrollmentReceiver는 권한과 필수 extra만 검증한다.
  3. UI 처리는 Receiver에서 하지 않고 기존 ForegroundService action으로 전달한다.
  4. Service는 main thread에서 WindowManager.addView()를 수행한다.
  5. addView() 성공 뒤에만 SCREEN_APPLIED를 반환한다.
  6. 사용자 등록 성공, 취소 또는 실패 시 Service가 overlay를 제거하고 terminal result를 한 번만 반환한다.
  7. Launcher는 terminal result 또는 timeout 뒤 기존 PUI 화면을 복구한다.

Receiver는 짧게 끝나야 한다. 마이크 획득, 파일 저장, embedding 생성처럼 시간이 걸리는 처리는 현재처럼 Service가 소유한다.

3.2 앱 간 message contract v1

아래 이름은 구현 시 상수 파일로 고정할 제안값이다. UI 문구나 색상과 독립적인 IPC 계약이므로 UI 가이드가 바뀌어도 유지한다.

항목 제안값 설명
open action com.skmagic.ondeviceai.action.SPEAKER_ENROLLMENT_OPEN Launcher → ondevice
event action com.skmagic.ondeviceai.action.SPEAKER_ENROLLMENT_EVENT ondevice → Launcher
protocol protocolVersion=1 호환되지 않는 버전은 거부
correlation requestId 요청부터 terminal result까지 동일한 UUID
source entrySource=PUI, LLM, INTERNAL 닫기·복귀 정책 선택
target targetScreen=REGISTER, MANAGE 처음 표시할 overlay
event REQUEST_ACCEPTED, SCREEN_APPLIED, COMPLETED, CANCELLED, FAILED 단계 또는 종료 상태
reason reasonCode 기계 판독 가능한 실패·거부 사유

보안과 개인정보 원칙:

권장 reason code:

reasonCode 의미 재시도
PRIVACY_MODE Privacy 정책상 진입 불가 정책 해제 후 가능
SCREEN_CONFLICT VitalSign/Security 등 충돌 화면 queue 또는 나중에 재시도
SERVICE_NOT_READY ForegroundService 초기화 전 가능
OVERLAY_PERMISSION_DENIED SYSTEM_ALERT_WINDOW 사용 불가 시스템 설정 필요
ALREADY_VISIBLE 동일 overlay 표시 중 기존 요청에 attach
ALREADY_RECORDING 등록 녹음 진행 중 기존 요청 유지
AUDIO_ACQUIRE_FAILED 등록용 AudioRecord 획득 실패 가능
NO_VALID_SAMPLE 유효 샘플 없음 재녹음
EMBEDDING_FAILED profile 생성·저장 실패 원인 확인 후 가능
TIMEOUT Launcher가 terminal result를 받지 못함 상태 조회 후 가능

3.3 Service 내부 명령

외부 Receiver가 private ForegroundService에 전달할 action은 앱 내부 상수로 분리한다.

ACTION_SHOW_SPEAKER_ENROLLMENT
  requestId
  entrySource
  targetScreen

ACTION_DISMISS_SPEAKER_ENROLLMENT
  requestId
  dismissReason

onStartCommand()은 action을 기존 handleAction()으로 넘기므로, 여기에 화자 등록 action 분기만 추가하면 된다. Receiver가 Service의 private 함수를 직접 호출하거나 Activity를 실행하지 않는다.

Service가 보관해야 할 최소 session:

data class SpeakerEnrollmentSession(
    val requestId: String,
    val entrySource: EntrySource,
    val targetScreen: TargetScreen,
    val startedAtElapsedMs: Long,
    var state: EnrollmentUiState,
    var terminalResultSent: Boolean = false,
)

requestId가 같은 재전송은 idempotent하게 처리하고, 다른 요청이 이미 진행 중이면 정책에 따라 기존 session에 attach하거나 ALREADY_RECORDING으로 거부한다.

3.4 UI·녹음 상태 머신

화자 등록 Overlay UI 상태와 진입 경로별 종료 정책

상태 머신 SVG 원본 크게 보기

상태 표시/처리 가능한 다음 상태
IDLE overlay 없음 SHOW_REQUESTED
SHOW_REQUESTED main thread에 표시 예약 VISIBLE, FAILED
VISIBLE 이름 입력 및 녹음 시작 가능 RECORDING, CANCELLED
RECORDING STT 정지, 등록 AudioRecord 독점 FINALIZING, CANCELLED, FAILED
FINALIZING WAV 저장, embedding/profile 등록 COMPLETED, FAILED
COMPLETED 성공 결과 1회 전송 DISMISSING
CANCELLED 취소 결과 1회 전송 DISMISSING
FAILED 실패 결과 1회 전송 DISMISSING 또는 재시도 가능한 VISIBLE
DISMISSING IME 숨김, removeView(), session 정리 IDLE

모든 종료 경로에서 다음 순서를 보장한다.

등록 녹음 중지
→ AudioRecord callback 해제
→ 필요 시 STT 소유권 복구
→ IME 숨김
→ WindowManager.removeView()
→ terminal result 1회 전송
→ session 정리

현재 onDestroy()는 녹음 중지와 등록 overlay 제거를 수행하지만 관리 overlay 제거와 결과 callback은 없다. 구현 시 두 overlay를 모두 정리하고 진행 중 외부 요청에는 FAILED/SERVICE_DESTROYED를 반환하도록 보강한다.

3.5 entrySource별 닫기·뒤로가기

현재 showSpeakerRegisterOverlay()의 닫기와 뒤로가기는 모두 다음과 같다.

stopSpeakerEnrollment()
→ hideSpeakerRegisterOverlay()
→ showSpeakerManageOverlay()

외부 PUI 진입에 그대로 사용하면 사용자가 닫기를 눌러도 다른 ondevice overlay가 다시 열리므로 자연스럽지 않다. 목표 동작은 다음처럼 분리한다.

entrySource 등록 화면 뒤로가기 닫기 등록 완료
INTERNAL 관리 overlay 복귀 관리 overlay 복귀 관리 overlay 복귀 또는 성공 표시
PUI 모든 overlay 닫기 + CANCELLED 동일 모든 overlay 닫기 + COMPLETED, PUI 복귀
LLM 모든 overlay 닫기 + CANCELLED 동일 모든 overlay 닫기 + COMPLETED, task 완료

Android system back, 화면 닫기 버튼, timeout, service destroy도 동일한 finishEnrollmentSession() 경로로 수렴시켜 terminal result 중복을 막는다.

3.6 Launcher 완료 의미

두 완료 단계를 섞지 않는다.

SCREEN_APPLIED
  = overlay가 실제 WindowManager에 추가됨
  = setLauncherScreen 작업의 성공 후보

COMPLETED
  = 유효 샘플 저장 + embedding/profile 등록 성공
  = 화자 등록 workflow의 성공

PUI 버튼은 SCREEN_APPLIED 뒤 사용자 상호작용을 기다리고, LLM/TaskManager가 “화자 등록 완료”까지 요구한 경우에만 COMPLETED를 terminal 기준으로 사용한다. 화면 표시 timeout과 등록 workflow timeout은 서로 다른 timer로 둔다.

4. UI 가이드 반영 계약

UI 가이드가 제공되면 기존 app/src/main/res/layout/overlay_speaker_register.xml과 관련 drawable, color, string을 교체해 구현할 수 있다. 통신·오디오·상태 머신과 View 렌더링을 분리하면 시안 변경이 기능 로직에 영향을 주지 않는다.

4.1 현재 UI 기준선

현재 코드에서 확인된 값:

항목 현재 구현
Window type Android O 이상 TYPE_APPLICATION_OVERLAY
크기 화면 너비 100%, 화면 높이의 90% 이상
위치 화면 중앙
입력 한국어 locale의 단일 행 화자 이름 EditText
주요 동작 녹음 시작/종료 toggle
보조 동작 뒤로가기, 닫기, 전체등록, 초기화
안내 문구 동일 이름 5회, 녹음별 5초 이상 권장
keyboard overlay 표시 후 이름 입력에 focus하고 IME 표시

이는 기능 검증용 기준선이며 최종 제품 UI 확정값은 아니다.

4.2 UI 가이드에서 받아야 할 항목

영역 필요한 가이드 미제공 시 임시 기준
화면 규격 해상도, 방향, safe area, PUI 헤더 유지 여부 현재 기기 display metrics
배경 dim 강도, modal/card/full-screen 여부 현재 overlay 배경 유지
typography font family, 크기, weight, 줄간격 기존 speaker style
색상 surface, primary, warning, disabled, focus 기존 resource 유지
버튼 순서, 크기, primary/secondary, icon 현재 ID를 유지하고 skin 교체
문구 제목, 안내, 동의, 오류, 완료 기존 한국어 문구 + TBD
녹음 표현 timer, waveform, 단계, 남은 횟수 시작/종료 text toggle
성공/실패 toast, inline, 완료 scene, 자동 닫기 시간 결과 후 즉시 닫기 제안
keyboard 화면 키보드/음성 입력, focus 정책 현재 Android IME
접근성 focus order, content description, 대비, 글자 확대 Android 기본 + 검증 필요
motion 등장/퇴장, 상태 전환 duration 150~250ms fade 제안
정책 버튼 전체등록·초기화 노출 대상 일반 PUI에서는 숨김 제안

특히 전체등록초기화는 개발·관리 성격이 강하므로 일반 사용자 PUI에 노출할지 제품 정책 확인이 필요하다. UI 가이드 전에는 삭제하지 않고 visibility 정책으로 분리한다.

4.3 UI 상태별 화면 산출물

UI 가이드는 최소 다음 상태를 포함하면 그대로 구현 가능하다.

  1. 최초 진입/이름 입력
  2. 이름 미입력 validation
  3. 녹음 준비
  4. 녹음 중
  5. 녹음 처리 중
  6. 등록 성공
  7. 재시도 가능한 실패
  8. 취소 확인이 필요한 경우
  9. 중복 이름 또는 기존 profile 처리
  10. Privacy/마이크 사용 안내

각 화면에 normal, pressed, focused, disabled 상태와 최종 문구가 있으면 XML resource와 상태 renderer로 옮긴다. Figma, SVG/PNG, 해상도 스펙, color/font token 중 제공 가능한 형식으로 전달하면 된다.

4.4 변경에 강한 구현 경계

SpeakerEnrollmentReceiver / IPC contract
            │ 변경하지 않음
SpeakerEnrollmentSession + state reducer
            │ UI 상태만 전달
SpeakerEnrollmentOverlayController
            │ inflate / render / dismiss
XML + drawable + color + string
            │ UI 가이드에 따라 교체

버튼 listener 안에서 직접 저장·결과 전송을 모두 처리하지 않고 onRecordClicked, onBackClicked, onCloseClicked 이벤트를 controller로 보내면 UI 레이아웃이 바뀌어도 기능 동작을 재사용할 수 있다.

5. Receiver와 Activity 중 무엇이 맞나

장점 제약 현재 판단
보호된 Receiver + 기존 overlay 기존 코드 재사용, 변경량 작음, 빠른 실기기 검증 Window overlay 수명주기를 서비스가 계속 관리 1차 구현 추천
전용 exported Activity + bound service back stack, IME, 접근성, lifecycle이 자연스러움 서비스 private 등록 상태를 controller로 분리해야 함 장기 제품 UX 추천
Launcher에 등록 UI 복제 Launcher 단독 UX 가능 녹음/저장/embedding 책임 중복, IPC 확대 비추천
기존 비공개 Activity를 단순 export 구현은 짧음 호출자·상태·권한 계약 부실 비추천
보호 없는 implicit broadcast 연결이 쉬움 제3자 호출과 spoofing 가능 금지

기존 Phase 1 문서는 장기 제품형 구조로 Launcher-native UX + ondevice 등록 엔진 경계를 제안했다. 이번 코드 발견으로 현재 제품 브랜치의 빠른 통합 경로는 ondevice overlay 재사용이 더 현실적이라는 사실이 추가됐다. 두 설계는 경쟁안이 아니라 단계가 다르다.

Phase 1A: protected entrypoint + existing ondevice overlay
Phase 1B: enrollment controller/API 분리
Phase 1C: Launcher-native product UX + bound service/AIDL

6. 화면·오디오·TaskManager 정책

6.1 화면 충돌

진입 전에 최소한 다음 상태를 결정해야 한다.

정책은 allow, queue, reject 중 하나로 명시하고 reason code를 남긴다.

6.2 마이크와 STT

현재 등록 구현은 STT 녹음을 중지하고 등록 client가 AudioRecord를 독점한 뒤 복구한다. 따라서 STT와 등록 녹음을 동시에 수행하는 새 fan-out은 필요하지 않다.

다만 다음 종료 경로에서도 반드시 복구돼야 한다.

6.3 화자인식 추론 구조와의 연결

등록 화면은 화자 embedding을 생성해 profile에 저장하는 producer다. 실제 음성 turn에서는 CPU STT와 QNN speaker identification이 병렬 실행되고 hard join 뒤 VOICE_ID를 확정하는 consumer 구조로 연결된다.

PUI 등록
  -> speaker profile / embedding 저장

일반 발화
  -> CPU STT ----------------------┐
  -> QNN speaker identification ---┤ hard join
                                   -> text + VOICE_ID
                                   -> profile/personalization lookup

자세한 추론 구조는 CPU STT + QNN 화자인식 병렬 통합 문서Speaker Context Contract에서 이어서 본다.

7. 구현 순서

  1. UI 가이드의 확정 항목과 TBD를 4장 표에 채우고 PUI 최초 화면을 REGISTER 또는 MANAGE로 결정한다.
  2. 설치본 0.285와 MR6 0.277setLauncherScreen, completion, domain policy 차이를 대조한다.
  3. ondevice에 signature permission, explicit Receiver, service action, idempotency guard를 추가한다.
  4. session/state reducer와 source별 닫기 정책을 단위 테스트한다.
  5. adb explicit intent로 ondevice 단독 진입과 STT stop/restore를 검증한다.
  6. SKMLauncher에 speakerRegistration enum과 공통 launch 함수를 추가한다.
  7. PUI 버튼 경로를 연결한다.
  8. DeviceAgent callback allowlist와 TaskDomainResourcePolicy를 확장한다.
  9. REQUEST_ACCEPTED, SCREEN_APPLIED, CANCELLED, FAILED, TIMEOUT을 실기기 log로 검증한다.
  10. 제품 UX가 확정되면 overlay를 전용 Activity/controller 구조로 단계적으로 옮긴다.

8. 최소 검증 매트릭스

구분 케이스 합격 조건
보안 권한 없는 앱이 intent 전송 Receiver 실행 거부
진입 PUI 버튼 요청한 targetScreen overlay 1회 표시
진입 setLauncherScreen=speakerRegistration 같은 target 정책으로 overlay 표시
중복 빠른 연속 요청 overlay 중복 생성 없음
오디오 등록 시작 일반 STT 녹음 중지, 등록 client 획득
오디오 완료/취소/실패 STT 녹음 복구
화면 VitalSign/Security/Privacy 충돌 정책대로 queue 또는 reason 포함 거부
lifecycle service 재시작 중 요청 crash 없이 retryable failure
완료 intent만 수신 terminal success로 조기 보고하지 않음
완료 overlay add 성공 SCREEN_APPLIED 확인
등록 embedding 저장 성공 목록과 다음 화자 식별 turn에서 사용 가능
회귀 일반 WUW/F2/STT 등록 미사용 시 기존 동작 유지
UI PUI 진입 후 닫기 관리 overlay가 다시 뜨지 않고 PUI 복귀
UI INTERNAL 진입 후 뒤로가기 기존 관리 overlay 복귀
결과 success/cancel/error 경합 requestId당 terminal result 정확히 1회
복구 process/service destroy overlay 잔존 없음, STT 또는 실패 결과 정리
개인정보 result/log 검사 이름·WAV 경로·embedding 외부 노출 없음

8.1 구현 완료 정의

다음 조건을 모두 충족해야 “연동 구현 완료”로 판단한다.

9. 최종 판단

구현은 가능하며 새 화면을 처음부터 만드는 작업보다 작다. 현재 ondevice가 이미 UI와 녹음/등록 상태를 소유하므로, PUI/Launcher는 화면 선택과 정책만 담당하고 ondevice의 보호된 entrypoint를 호출하는 구조가 1차 목표에 맞다.

제품형 Launcher-native UX는 이후 controller/API를 분리한 다음 진행한다. 지금 바로 UI와 AudioRecord를 Launcher로 옮기면 이미 동작하는 등록 경로를 복제하고 앱 간 PCM 전달, 취소, timeout, 저장 책임까지 동시에 새로 설계해야 하므로 리스크가 커진다.

현재 문서는 구현에 착수할 수 있는 계약 수준까지 정리됐으며, UI 가이드에서 미정인 항목은 4장에 격리했다. 이후 UI 가이드가 제공되면 화면 리소스와 renderer 부분을 확정하고, 사용자가 구현을 요청하는 시점에 Launcher와 ondevice 두 저장소의 코드를 이 기준으로 변경한다.

Connections

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date