deel-local-cli 1.7.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.ko.md +1166 -0
  2. package/README.md +1223 -1107
  3. package/bin/deel.js +78 -12
  4. package/package.json +4 -4
  5. package/src/acp/map.js +1 -1
  6. package/src/acp/serve.js +40 -3
  7. package/src/agent/compact.js +314 -296
  8. package/src/agent/effort.js +27 -7
  9. package/src/agent/evidence.js +2 -0
  10. package/src/agent/filemem.js +141 -0
  11. package/src/agent/grade.js +51 -1
  12. package/src/agent/loop.js +218 -40
  13. package/src/agent/session.js +136 -14
  14. package/src/agent/store.js +186 -9
  15. package/src/agent/threads.js +26 -1
  16. package/src/backend/adapter.js +272 -23
  17. package/src/backend/learn.js +24 -0
  18. package/src/backend/mcp.js +96 -5
  19. package/src/backend/probe.js +131 -61
  20. package/src/backend/quota.js +29 -5
  21. package/src/backend/retry.js +3 -0
  22. package/src/backend/scanui.js +1 -1
  23. package/src/backend/toolfit.js +325 -0
  24. package/src/commands.js +170 -61
  25. package/src/completion.js +20 -2
  26. package/src/config.js +47 -2
  27. package/src/i18n/en.js +210 -3
  28. package/src/i18n/index.js +40 -0
  29. package/src/i18n/ja.js +204 -3
  30. package/src/i18n/ko.js +270 -3
  31. package/src/i18n/zh.js +204 -3
  32. package/src/lsp/client.js +49 -5
  33. package/src/oneshot.js +92 -5
  34. package/src/pack/sbom.js +30 -4
  35. package/src/pack/selfpack.js +26 -10
  36. package/src/pack/sheet.en.js +288 -0
  37. package/src/pack/tar.js +65 -2
  38. package/src/plugins/manage.js +46 -9
  39. package/src/repl.js +344 -61
  40. package/src/reset.js +397 -0
  41. package/src/safety/audit.js +95 -8
  42. package/src/safety/authcmd.js +316 -0
  43. package/src/safety/guard.js +143 -0
  44. package/src/safety/keystore.js +114 -38
  45. package/src/safety/undo.js +25 -6
  46. package/src/tools/desc.en.js +19 -14
  47. package/src/tools/index.js +349 -75
  48. package/src/tools/jobs.js +175 -42
  49. package/src/tools/lsp.js +5 -4
  50. package/src/tools/outline.js +7 -3
  51. package/src/tools/task.js +10 -6
  52. package/src/tools/todo.js +9 -2
  53. package/src/tools/verify.js +42 -7
  54. package/src/tools/webfetch.js +94 -10
  55. package/src/ui/export.js +1 -1
  56. package/src/ui/md.js +201 -5
  57. package/src/ui/motion.js +0 -1
  58. package/src/ui/pastechip.js +50 -3
  59. package/src/ui/pick.js +115 -0
  60. package/src/ui/screen.js +23 -3
  61. package/README.en.md +0 -1117
package/README.md CHANGED
@@ -1,1107 +1,1223 @@
1
- <div align="center">
2
-
3
- <picture>
4
- <source media="(prefers-color-scheme: dark)" srcset="docs/assets/hero-ko-dark.svg">
5
- <img alt="deel — 컴퓨터 안에서만" src="docs/assets/hero-ko-light.svg" width="620">
6
- </picture>
7
-
8
- ### 로컬 모델과 사내 게이트웨이로 도는 코딩 에이전트 CLI
9
-
10
- 의존성 0개 · Node 20+ · 소스가 나가는 자리는
11
-
12
- 바깥 API 붙습니다**말했을 때만**
13
-
14
- <br>
15
-
16
- [![npm](https://img.shields.io/npm/v/deel-local-cli?logo=npm&logoColor=white&label=npm&color=cb3837)](https://www.npmjs.com/package/deel-local-cli)
17
- [![downloads](https://img.shields.io/npm/dt/deel-local-cli?label=downloads&color=1a7f37)](https://www.npmjs.com/package/deel-local-cli)
18
- [![node](https://img.shields.io/node/v/deel-local-cli?logo=nodedotjs&logoColor=white&label=node&color=5FA04E)](https://nodejs.org)
19
- [![license](https://img.shields.io/npm/l/deel-local-cli?label=license&color=0969da)](LICENSE)
20
-
21
- [![Node.js CI](https://img.shields.io/github/actions/workflow/status/jysvai/deel-local-cli/test.yml?branch=main&logo=github&logoColor=white&label=Node.js%20CI)](https://github.com/jysvai/deel-local-cli/actions/workflows/test.yml)
22
- [![CodeQL](https://img.shields.io/github/actions/workflow/status/jysvai/deel-local-cli/codeql.yml?branch=main&logo=github&logoColor=white&label=CodeQL)](https://github.com/jysvai/deel-local-cli/actions/workflows/codeql.yml)
23
- [![tests](https://img.shields.io/badge/tests-5%2C685%20passing-1a7f37?logo=checkmarx&logoColor=white)](docs/ko/develop.md)
24
-
25
- [![dependencies](https://img.shields.io/badge/dependencies-0-1a7f37)](https://www.npmjs.com/package/deel-local-cli?activeTab=dependencies)
26
- [![ESM](https://img.shields.io/badge/ESM-Node%2020%2B-5FA04E?logo=javascript&logoColor=white)](package.json)
27
- [![network](https://img.shields.io/badge/network-127.0.0.1%20only-1a7f37?logo=wireguard&logoColor=white)](#데이터가-나가는-길)
28
- [![telemetry](https://img.shields.io/badge/telemetry-none-1a7f37?logo=ghostery&logoColor=white)](#데이터가-나가는-길)
29
-
30
- **[English](README.en.md)** · [사내 반입 안내](#사내-반입) · [문제 해결](#문제-해결) · [자세한 문서](docs/ko/)
31
-
32
- </div>
33
-
34
- ---
35
-
36
- ```
37
- ╭──────────────────────────────────────────────────────────────╮
38
- │ deel 1.7.0 ⌂ 이 안 OpenAI 호환 규격 │
39
- │ │
40
- 모델 qwen2.5-coder:7b (40k 토큰) │
41
- │ 보냄 이 컴퓨터 안 127.0.0.1:11434 ← 여기 말고는 어디로도 안 갑니다 │
42
- │ 연결 스트리밍 · 도구 · 추론 조절 │
43
- 폴더 C:\work\myproject │
44
- 승인 ⏵⏵ 자동 승인 — 묻고 고칩니다. 되돌리기(/undo)가 안전망입니다
45
- │ Shift+Tab 으로 바꿉니다 · Tab 치던 / 명령을 채웁니다 │
46
- PC 스킬 337 · 명령 127 · 플러그인 42 │
47
- ╰──────────────────────────────────────────────────────────────╯
48
- /help 명령 목록 /think 추론 강도 Ctrl+C 중단·끝내기
49
-
50
- ▏myproject · qwen2.5-coder:7b ▰▰▱▱▱▱▱▱▱▱ 22% 28k/128k 종합 · ◇ medium·절약 · ⏵⏵ 자동
51
- ❯ 로그 형식 통일해줘
52
-
53
- Grep(console.log)
54
- 1개 파일 · 1건
55
- ◧ Read(src/runner.js)
56
- └ 5줄
57
- Edit(src/runner.js)
58
- 1군데
59
-
60
- ▌ 로그 호출을 logger 형식으로 통일했습니다. runner.js 한 군데를 고쳤습니다.
61
-
62
- ── 4.2초 · 도구 3회 · ↑3,900 ↓180
63
- ```
64
-
65
- ---
66
-
67
- ## 목차
68
-
69
- - [왜 만들었나](#왜-만들었나)
70
- - [무엇이 다른가](#무엇이-다른가)
71
- - [빠른 시작](#빠른-시작)
72
- - [데이터가 나가는 길](#데이터가-나가는-길)
73
- - [바깥 API 붙이기](#바깥-api-붙이기)
74
- - [로컬 모델 여러 개 쓰기](#로컬-모델-여러-개-쓰기)
75
- - [대화 중 명령](#대화-중-명령)
76
- - [작업 모드](#작업-모드)
77
- - [쉬움 · 개발자](#쉬움--개발자)
78
- - [도구](#도구)
79
- - [한글 문서와 엑셀](#한글-문서와-엑셀)
80
- - [만든 웹을 그 자리에서 띄웁니다](#만든-웹을-그-자리에서-띄웁니다)
81
- - [스킬·플러그인](#스킬플러그인)
82
- - [추론 강도](#추론-강도)
83
- - [자동 압축](#자동-압축)
84
- - [대화 이어하기](#대화-이어하기)
85
- - [밖에서 도구 붙이기 (MCP)](#밖에서-도구-붙이기-mcp)
86
- - [에디터 안에서 쓰기 (ACP)](#에디터-안에서-쓰기-acp)
87
- - [비밀이 새지 않게](#비밀이-새지-않게)
88
- - [안전망](#안전망)
89
- - [사내 반입](#사내-반입)
90
- - [설정](#설정)
91
- - [문제 해결](#문제-해결)
92
- - [개발](#개발)
93
- - [릴리스 노트](#릴리스-노트)
94
-
95
- 여기는 **요약**입니다. 절마다 붙은 링크를 따라가면 그 안의 이야기가 나옵니다.
96
-
97
- | 자세한 문서 | 무엇이 있나 |
98
- |---|---|
99
- | [모델 다루기](docs/ko/models.md) | 급과 창 크기 · 국산 모델 이름표 · 켤 때 프로젝트 읽기 |
100
- | [화면과 조작](docs/ko/interface.md) | 입력칸 · 작업 모드 · 쉬움과 개발자 · 무엇을 묻고 무엇을 그냥 하나 |
101
- | [도구 자세히](docs/ko/tools.md) | `Outline` · `Verify` · `Task` · `Jobs` · `Append` · `Def`/`Refs` · 편집 매칭 |
102
- | [한글 문서와 엑셀](docs/ko/documents.md) | hwpx·docx·pptx·**PDF** · 인코딩 · 엑셀 → CSV |
103
- | [늘려 쓰기](docs/ko/extend.md) | 스킬 · 플러그인 · MCP · ACP |
104
- | [속도와 씀씀이](docs/ko/tuning.md) | 단계별 추론 강도 · 프리픽스 캐시 · 컨텍스트 길이 |
105
- | [안전망과 사내 반입](docs/ko/safety.md) | 되돌리기 · 작업 범위 · 감사기록 · 심사 서류 |
106
- | [설정](docs/ko/config.md) · [개발](docs/ko/develop.md) | 환경변수 · 실행 옵션 · 검사 돌리기 · 폴더 구조 |
107
- | [릴리스 노트](docs/ko/releases.md) | [1.7.x](docs/ko/releases/1.7.md) · [1.6.x](docs/ko/releases/1.6.md) · [1.5.x](docs/ko/releases/1.5.md) · [1.4.x](docs/ko/releases/1.4.md) · [1.3.x](docs/ko/releases/1.3.md) · [1.2.x](docs/ko/releases/1.2.md) |
108
-
109
- ---
110
-
111
- ## 왜 만들었나
112
-
113
- 사내 보안 정책이 **미승인 소프트웨어 반입**을 막으면, 코딩 에이전트 도구는 대부분 쓸 수 없습니다.
114
- 의존성 수백 개가 딸려 오고, 설치할 스크립트가 돌고, 어디로 통신하는지 줄로 답할 수 없기 때문입니다.
115
-
116
- deel 심사를 통과하는 것을 목표로 만들었습니다.
117
-
118
- | | deel |
119
- |---|---|
120
- | 외부 의존성 | **0개** Node 내장 기능만 |
121
- | 설치 스크립트 | **없음** 압축 풀고 바로 실행 |
122
- | 소스가 나가는 자리 | **딱 곳** 직접 설정한 주소 |
123
- | 필요한 것 | Node 20 이상 |
124
-
125
- 직접 확인하실 수 있습니다.
126
-
127
- ```bash
128
- npm view deel-local-cli dependencies # {}
129
- npm view deel-local-cli scripts # install/postinstall 없음
130
- deel audit # 심사서 전문 출력
131
- ```
132
-
133
- ---
134
-
135
- ## 무엇이 다른가
136
-
137
- 로컬 모델을 상대하는 코딩 에이전트는 있습니다. 그런데 **로컬로 돌리는
138
- 전제로 속을 다시 설계한** 것은 드뭅니다.
139
-
140
- | | 다른 도구 | deel |
141
- |---|---|---|
142
- | `/undo` | 파일만 되돌린다 — 대화는 그 일이 있었다고 믿는 채로 | **대화까지** 같이 되감는다 |
143
- | 긴 대화 | 클라우드가 안 느끼는 비용을 로컬에서도 그대로 짊어진다 | 프리픽스 캐시가 **살아남게** 순서를 설계 |
144
- | 작은 모델의 편집 | 공백 하나 틀려도 실패 | 성공률 20%→**100%**, 엉뚱한 곳 0건 |
145
- | 국산 모델 | 겪어 보기 전엔 모른다 | 공개 문서로 **미리** 안다 |
146
- | "다 됐습니다" | 확인 안 된 것도 됐다고 한다 | `/evidence`·`/export` — **안 된 것까지** 적는다 |
147
- | MCP·ACP | SDK 가 필요하다 | `child_process` + `JSON` 뿐 |
148
- | 심사 서류 | 사람이 손으로 써서 실제와 어긋난다 | **코드가 소스를 훑어서** 만든다 |
149
-
150
- <br>
151
-
152
- #### `/undo` 는 파일과 대화를 같이 되감습니다
153
-
154
- 파일만 되돌리면 모델은 방금 그 편집을 했다고 계속 믿고 다음 턴을 그 위에
155
- 쌓습니다 — 화면에는 아무 일도 없었던 것처럼 보입니다. deel 은 되돌린 만큼
156
- 오간 메시지도 같이 접습니다. 접다가 도구 호출의 짝이 어긋나면 API 가 400 을
157
- 내므로, 짝을 다시 맞추는 로직(`repairToolPairs`)까지 같이 돕니다.
158
-
159
- #### 대화에서 로컬 모델이 갈수록 느려지는 이유를 직접 잡았습니다
160
-
161
- Ollama·llama.cpp 프롬프트 앞부분이 글자라도 바뀌면 전부를 다시
162
- 계산합니다. 클라우드 API 비용을 느끼니 신경 이유가 없지만,
163
- 로컬로 돌리는 사람에게는 대화가 길어질수록 턴마다 지연이 쌓입니다. deel
164
- 바뀔 있는 것(모드·핀)을 프롬프트 **맨 끝**으로 보내고, Ollama 에는
165
- `keep_alive: 60m` 을 같이 보내 앞부분이 캐시에 그대로 남게 합니다. 이 순서는
166
- 검사(`test/cache.test.js`)가 지킵니다.
167
-
168
- #### 작은 모델도 편집이 실제로 성공합니다
169
-
170
- 작은 로컬 모델은 고치려는 문자열을 공백 하나까지 완벽히 재현하지 못하는
171
- 경우가 흔합니다. `npm run bench` 내부 벤치마크에서, 정확히 일치만
172
- 요구하던 방식은 성공률 20% 였습니다. 지금 방식(공백·들여쓰기를 단계적으로
173
- 완화)은 **100%** 그러면서도 엉뚱한 곳을 고친 건수는 방식 **0건**
174
- 입니다. 모호하면 찾지 못했다고 말할지언정 짐작해서 고치지 않습니다.
175
-
176
- #### 국산 모델은 겪어 보기 전에 압니다
177
-
178
- EXAONE·HyperCLOVA X·Kanana·Midm·Solar 공개 문서로 확인 가능한 버릇(예:
179
- 추론형 여부)을 deel 미리 알고 시작합니다. 다른 도구는 모델들을
180
- 번도 만나 채로 취급하고, 사람이 턴을 겪어야 요령이 붙습니다.
181
-
182
- #### "다 됐습니다" 대신 증명서를 냅니다
183
-
184
- `/evidence` `/export` 무엇을 바꿨는지뿐 아니라 **무엇을 확인하지
185
- 못했는지**까지 적습니다. AI 코딩 도구가 사람을 제일 잘 속이는 순간이 자신
186
- 있게 "됐습니다" 라고 말할 때라는 걸 알기 때문입니다. `/export` 는 바깥
187
- 주소가 하나도 없는 자기완결 HTML 이라 폐쇄망 어디서든 열립니다.
188
-
189
- #### MCP·ACP SDK 없이 붙였습니다
190
-
191
- Model Context Protocol Agent Client Protocol 다 표준입출력으로 줄
192
- 단위 JSON-RPC 2.0 주고받는 전부입니다. deel 은 `child_process` 와
193
- `JSON` 만으로 구현했습니다 의존성 0개가 "기능을 결과" 가 아니라
194
- "안 필요해서" 라는 걸 이 두 가지가 보여 줍니다.
195
-
196
- #### 심사 서류를 손으로 씁니다
197
-
198
- `deel pack` 만드는 반입심사서·SBOM·감사 사양은 **코드가 소스를 훑어서**
199
- 만든 겁니다. 손으로 적은 서류는 언젠가 실제와 어긋나고, 담당자가 그걸 한 번
200
- 발견하면 나머지 서류도 믿습니다.
201
-
202
- ---
203
-
204
- ## 빠른 시작
205
-
206
- ### 설치
207
-
208
- ```bash
209
- npm install -g deel-local-cli
210
- ```
211
-
212
- 설치가 싫으면 소스를 받아 그대로 쓰셔도 됩니다. `npm install` 이 필요 없습니다.
213
-
214
- ```bash
215
- git clone https://github.com/jysvai/deel-local-cli
216
- node deel-local-cli/bin/deel.js
217
- ```
218
-
219
- > **주의** — 홈 디렉터리(`~`)에서 `npm install` 하지 마세요. 거기에 `node_modules` 가 생기면
220
- > 이후 모든 npm 명령이 폴더를 훑어서 무관한 패키지 경고를 냅니다. `-g` 로 설치하거나 `npx` 쓰세요.
221
-
222
- ### 연결 정하기
223
-
224
- 이 PC 에 떠 있는 로컬 서버를 훑어서 고르는 방법:
225
-
226
- ```bash
227
- deel scan --pick
228
- ```
229
-
230
- 주소를 직접 넣는 방법 (사내 게이트웨이는 이쪽):
231
-
232
- ```bash
233
- deel setup
234
- ```
235
-
236
- ### 시작
237
-
238
- 작업할 폴더에서 `deel` 칩니다. **그 폴더가 작업 범위가 되고, 밖의 파일은 읽지도 쓰지도 못합니다.**
239
-
240
- ```bash
241
- cd C:\work\myproject
242
- deel
243
- ```
244
-
245
- ---
246
-
247
- ## 데이터가 나가는 길
248
-
249
- 코딩 에이전트는 소스 코드를 통째로 모델에 보냅니다. **그 주소가 어디인지가 전부입니다.**
250
- 말로 보장하는 대신 코드가 막습니다 `src/safety/network.js` 요청마다 확인하고,
251
- 허용 목록에 없으면 요청을 만들지도 않습니다.
252
-
253
- ```
254
- [A] 모델 게이트웨이 ─── 소스 코드가 나가는 유일한
255
- setup 에서 정한 자리만. 모델을 바꾸면 이전 자리는 닫힙니다.
256
-
257
- [B] 웹 읽기 (WebFetch) ─ 받아 오기만 하는 길
258
- GET 만. 본문 0바이트. 사내망·로컬 주소는 거절. 다녀온 곳은 전부 기록.
259
-
260
- [C] 플러그인 받기 ────── /plugin install 때만 잠깐
261
-
262
- [D] MCP 서버 ─────────── 자식 프로세스, 남의 프로그램
263
- .deel/mcp.json 에 사람이 직접 적어야만 뜹니다. 기본은 꺼져 있습니다.
264
- ```
265
-
266
- A·B·C 는 deel 이 직접 만드는 요청이라 하나씩 걸러낼 수 있습니다. **[D] 는
267
- 다릅니다** MCP 서버는 별도 프로세스라 그 안에서 무슨 소켓을 여는지 코드로
268
- 볼 수 없습니다. 그래서 `--offline` 일 때는 요청을 거르는 대신 **그 서버
269
- 자체를 아예 띄우지 않습니다** — 막을 수 없는 것을 막았다고 말하지 않습니다.
270
-
271
- `--offline` 을 주면 **B·C·D 가 모두 막히고 이 컴퓨터 안으로만** 다닙니다.
272
-
273
- ```bash
274
- deel --offline
275
- ```
276
-
277
- 무엇이 어디로 있는지는 화면 위에 적혀 있습니다.
278
-
279
- ```
280
- deel 1.7.0 ⌂
281
- 보냄 이 컴퓨터 안 127.0.0.1:11434 ← 여기 말고는 어디로도 안 갑니다
282
- ```
283
-
284
- ### 실행 모드 셋
285
-
286
- 1.6 까지는 자물쇠가 `--offline` 하나였고 **기본이 열림**이었습니다.
287
- `.deel/config.json` 의 주소 한 줄만 바깥으로 바꾸면 그대로 나갔습니다.
288
- 화면에 `↗` 뜨긴 했지만 그건 **알리는 것**이지 막는 것이 아닙니다.
289
-
290
- | 모드 | 켜는 법 | 바깥 주소일 때 |
291
- |---|---|---|
292
- | `⌂ 이 안` | `deel` (처음 값) | **물어봅니다.** 한 번 허락하면 그 연결은 다음부터 안 묻습니다 |
293
- | `↗ 바깥` | `deel online` · `--online` | 안 물어봅니다 |
294
- | `⛊ 봉인` | `deel offline` · `--offline` | 기억해 둔 허가까지 무시합니다 (제일 셈) |
295
-
296
- **주소와 허가가 있어야 나갑니다.** 주소만 바꿔서는 나갑니다.
297
-
298
- 로컬·사내망(`127.x` · `10.x` · `192.168.x` · `172.16~31.x`)은 셋 중 어느
299
- 모드에서도 그냥 갑니다 — `offline` 은 「인터넷 없음」 이 아니라 「회사 밖으로
300
- 나감」 입니다.
301
-
302
- 수집·전송하는 것이 없습니다. 텔레메트리, 사용 통계, 오류 보고 전부 없습니다.
303
- 대화 기록·되돌리기 이력·설정은 작업 폴더의 `.deel/` 안에만 남습니다.
304
-
305
- > 검증: `npm test` 의 network·web·mcp 검사 159항목. 허용되지 않은 서버에 실제로
306
- > 요청이 **한 건도 닿지 않는지**, `--offline` 일 때 MCP 서버가 **한 번도 안
307
- > 뜨는지**까지 진짜 서버를 띄워서 확인합니다.
308
-
309
- ---
310
-
311
- ## 바깥 API 붙이기
312
-
313
- 로컬 모델이 도구의 기본값이고, 그건 바뀝니다. 다만 「사내에 GPU 가 없다」
314
- 「이 가지만 모델로 하고 싶다」 자리가 있어서, 벤더 API 도 붙을 수
315
- 있게 열었습니다. **위의 모드가 그 문을 지킵니다.**
316
-
317
- ```bash
318
- deel setup
319
- ```
320
-
321
- 주소를 묻는 대신 **어디에 붙을지**를 묻습니다.
322
-
323
- ```
324
- 1. 열쇠만 있습니다 — 어디 것인지 찾아 드립니다 빈칸 1개
325
- 2. 주소를 직접 넣기 (사내 게이트웨이 · 로컬) 빈칸 2개
326
- 3. OpenAI (GPT) 빈칸 1개
327
- 4. Anthropic (Claude) 빈칸 1개
328
- 5. Google (Gemini) 빈칸 1개
329
- 6. AWS Bedrock 빈칸 2개
330
- ```
331
-
332
- 1번이 핵심입니다. 열쇠 앞머리로 어디 것인지 짚어서 **한 곳만** 묻습니다.
333
-
334
- ```
335
- ❯ sk-ant-api03-••••
336
- ✓ Anthropic (Claude) 열쇠로 보입니다. (열쇠가 sk-ant- 로 시작합니다)
337
- 여기저기 던지지 않습니다.
338
- ```
339
-
340
- 벤더마다 찔러 보는 식으로 만들면 Anthropic 열쇠가 OpenAI 서버로, 다시 Google
341
- 서버로 갑니다. 401 오고 끝이지만 **열쇠는 이미 갔습니다.** 그래서 모르는
342
- 열쇠는 짐작하지 않고 사람에게 묻습니다.
343
-
344
- Bedrock 리전을 고릅니다 — 서울(`ap-northeast-2`) 포함 다섯 곳과 「직접 입력」.
345
- Claude 는 몸통 규격이 달라서 여섯 자리를 따로 흡수했습니다
346
- ([1.7.0 릴리스 노트](docs/ko/releases/1.7.md#170)).
347
-
348
- ### 바깥에 붙으면 파일 비밀도 가립니다
349
-
350
- 로컬만 때는 파일에서 읽어 글을 **일부러 가렸습니다** — 가리면 모델이
351
- 그 가림표를 다시 파일에 써서 사람의 진짜 열쇠를 지워 버리기 때문입니다.
352
-
353
- 바깥으로 나가면 저울이 뒤집힙니다. `Read` 번이면 `.env` 통째로 남의
354
- 서버 로그에 남고, 그건 되돌릴 수가 없습니다. 잃는 쪽은 다른 자리에서 막았습니다
355
- `Write`·`Append`·`Edit` 이 가린 표를 파일에 못 씁니다.
356
-
357
- ### 얼마 나갔는지 보입니다
358
-
359
- ```
360
- 12.4초 · 도구 3회 · ↑8.2k ↓1.1k · $0.0271
361
- ```
362
-
363
- **값이 박힌 요금표가 없습니다.** 요금은 회사가 아무 때나 바꾸는 값이라, 소스에
364
- 박아 두면 반년 도구는 틀린 금액을 자신 있게 찍는 도구가 됩니다.
365
- `.deel/config.json` 에 적으면 셈합니다 — 100만 토큰당 달러입니다.
366
-
367
- ```json
368
- "요금": { "claude-opus-4-6": { "입력": 0, "출력": 0, "기준": "2026-09-01" } }
369
- ```
370
-
371
- 금액 옆에 **어디서 온 값인지·언제 기준인지**가 같이 뜨고, 반년이 지나면
372
- 오래됨` 붙습니다. 모르면 안 찍습니다 — 로컬로만 쓰는 화면에는 돈 이야기가
373
- 아예 안 뜹니다.
374
-
375
- ---
376
-
377
- ## 로컬 모델 여러 개 쓰기
378
-
379
- 로컬 런타임은 보통 하나만 쓰지 않습니다. Ollama 로 작은 모델을 돌리면서
380
- LM Studio 로 큰 모델을 띄워 두기도 합니다. `deel scan` 이 알려진 자리 13곳을 동시에 두드려
381
- 전부 찾아냅니다.
382
-
383
- ```
384
- $ deel scan
385
-
386
- ── 로컬 모델 서버 훑기 ───────────────────────────────────────────────
387
- 127.0.0.1 알려진 자리 13곳을 두드립니다. 바깥으로는 나가지 않습니다.
388
-
389
- 3곳 찾음
390
-
391
- ◆ Ollama 127.0.0.1:11434 Ollama 규격 36ms
392
- · qwen2.5-coder:7b 7B · 4.4GB
393
- · llama3.2:1b 1B · 1.2GB
394
- ◆ LM Studio 127.0.0.1:1234 OpenAI 호환 7ms
395
- · devstral-small-2507
396
- llama.cpp 127.0.0.1:8080 OpenAI 호환 7ms
397
- · gemma-3-4b-it
398
-
399
- 합계 서버 3곳 · 모델 6개
400
-
401
- 추천 Ollama · qwen2.5-coder:7b
402
- 코딩용 모델 · 도구 호출을 잘하는 계열
403
- ```
404
-
405
- 포트로 단정하지 않고 **응답을 보고** 런타임을 구분합니다 Ollama `/api/version`,
406
- LM Studio `/api/v0/models`, llama.cpp `/props`. 알아보면 `(추정)` 이라고 밝힙니다.
407
-
408
- | 명령 | 하는 일 |
409
- |---|---|
410
- | `deel scan` | 찾아서 보여주기만 |
411
- | `deel scan --pick` | 목록에서 골라 등록 |
412
- | `deel scan --save` | 찾은 전부 등록 |
413
- | `deel scan --ports 9000,9100` | 기본 자리 말고 더 볼 포트 |
414
- | `deel scan --host <주소>` | 기본은 `127.0.0.1` |
415
- | `deel scan --key <키>` | 키가 필요한 로컬 서버일 |
416
-
417
- 등록한 뒤에는 대화 `/model` 갈아탑니다. **대화 내용은 그대로 이어집니다.**
418
-
419
- > **자세히** 걸린 모델에 맞춰 스스로 바뀝니다 · 국산 모델은 겪기 전에 압니다 · 작은 창에서는 고정 몫을 줄입니다 · 켤 때 이 폴더가 무슨 프로젝트인지 읽습니다
420
- >
421
- > **[모델 다루기 읽기 →](docs/ko/models.md#로컬-모델-여러-개-쓰기)**
422
-
423
- ---
424
-
425
- ## 대화 명령
426
-
427
- 이름은 Claude Code / Codex 관례에 맞췄습니다.
428
-
429
- | 명령 | 하는 일 |
430
- |---|---|
431
- | `/help` | 명령 목록 |
432
- | `/bell [on|off]` | 다 됐을 때·물어볼 때 종소리와 창 제목 |
433
- | `/lang [ko|en|ja|zh] [시킬말]` | 화면 말 (한국어·English·日本語·中文 네 가지, 전부 다 채워져 있다). **시킬 말을 따로 줄 수 있다** — `/lang ko en` 이면 모델에게는 영어로 시키고 답은 한국어로 받는다(8k 창에서 고정 몫 23% 감소). 코드는 그대로 |
434
- | `/keys` | 터미널이 무슨 키를 보내는지 눌러서 확인 줄바꿈이 |
435
- | `/consult <프로필> <질문>` | 다른 모델에게 물어보기지금 쓰는 것은 안 바꿈 |
436
- | `/export` | 대화를 **보고서 한 장**(HTML)으로 — 시킨 것·바뀐 것·확인한 것. 폐쇄망에서 여는 자기완결 파일 |
437
- | `/lsp [on\|off]` | 언어 서버 — 무엇이 깔려 있고 `Def`·`Refs` 를 쓸 수 있는지. `off` 는 고친 뒤 진단만 끔 |
438
- | `/context` | 무엇이 컨텍스트를 먹고 있는지 |
439
- | `/ctx [auto\|숫자\|자세히]` | 컨텍스트 **길이** — 모델에 맞춰 다시 재거나 직접 지정 |
440
- | `/out [숫자\|auto]` | 번에 받을 **답 길이** 상한 — 큰 파일이 잘리면 여기를 올립니다 |
441
- | `/grade [작음\|보통\|큼\|auto]` | 모델 **급** — 얼마나 알아서 하나. `/ctx` 와 다른 축입니다 |
442
- | `/compact` | 앞선 대화를 요약해서 접기 |
443
- | `/clear` | 대화 비우기 (연결·규칙은 유지) |
444
- | `/thread [new\|fork\|close\|번호]` | 대화 갈래 곁가지를 자리에서. 연결·되돌리기는 같이 씁니다 |
445
- | `/learned [지우기]` | 쓰면서 저절로 알게 된 것 — 되는 명령·이 모델의 버릇 |
446
- | `/pin <말>` | 못 박기 — 접거나 요약해도 **안 지워지는** 말 |
447
- | `/evidence [파일]` | 증거 무엇을 바꿨고 무엇이 그걸 증명하나. **안 된 것도** 적습니다 |
448
- | `/commit [전부\|미리보기\|제목]` | 이번 대화가 바꾼 것만 담아 커밋. 메시지는 diff 와 증거에서. **push 는 안 합니다** |
449
- | `/model` | 연결·모델 바꾸기 |
450
- | `/model 카드` | 이 모델을 겪어 본 결과 — 그래서 deel 이 무엇을 바꿔 뒀는지 |
451
- | `/think <강도>` | 추론 강도 (`off·low·medium·high·max`) |
452
- | `/think 배분 <배분>` | 단계별 배분 (`균일·절약·깊게`) |
453
- | `/think 자세히` | 단계표 — 어느 단계를 어떤 강도·상한으로 도는지 |
454
- | `/mode <모드>` | 승인 정책 — 얼마나 물어보나 (`auto` · `confirm` · `strict`) |
455
- | `/work [모드]` | 작업 모드 — 무슨 일을 하는 중인가 |
456
- | `/auto` | 다시 맡기기 말을 보고 알맞은 모드로 저절로 옮겨 갑니다 |
457
- | `/code` `/plan` `/architect` `/debug` `/ask` `/orchestrator` | 작업 모드 바로 바꾸기 (그때부터 고정) |
458
- | `/level [수준]` | 화면에 무엇을 내놓을지 (`쉬움` · `개발자`) |
459
- | `/motion [기본\|기사\|동물\|사무실\|끔]` | 일하는 동안 뭐가 도나 — 그 자리에서 바뀌고 설정에 남습니다 |
460
- | `/undo [턴수]` | 파일 변경 되돌리기 |
461
- | `/diff [파일]` | 이번 대화에서 바뀐 파일 · 바뀐 자리 보기 |
462
- | `/preview [폴더\|파일\|off]` | 만든 웹을 이 자리에서 띄워 보기 — 브라우저가 같이 열립니다 |
463
- | `/tools` | 있는 도구 |
464
- | `/skills [검색어\|all\|off]` | 스킬 보기·검색·골라 올리기 |
465
- | `/plugin [install\|remove\|pack]` | 플러그인 관리 |
466
- | `/cost` | 이번 세션 사용량 |
467
- | `/status` | 연결 상태 |
468
- | `/scan [save]` | PC 있는 로컬 모델 서버 훑기 (`save` 바로 등록) |
469
- | `/sessions` | 이 폴더의 지난 대화 목록 |
470
- | `/recall <말>` | 지난 대화에서 **내용으로** 찾기 |
471
- | `/memory` | 대화가 끝나도 남는 기억 보기·적기·지우기 |
472
- | `/mcp` | 밖에서 붙인 도구(MCP) 서버 보기 |
473
- | `/init` | `DEEL.md` 규칙 파일 만들기 |
474
- | `/exit` | 끝내기 |
475
-
476
- `/scan` `/sessions` 는 나가지 않고도 씁니다. 로컬 서버를 새로 켰거나 모델을
477
- 바꿔 올렸을 때 `/scan save` → `/model` 두 번이면 대화를 이어둔 채로 갈아탑니다.
478
-
479
- **치지 않고 쓰는 것**
480
-
481
- | 키 | 무엇을 |
482
- |---|---|
483
- | `Tab` | 치던 `/` 명령을 채웁니다. 치는 도중에 후보가 상자 아래에 뜹니다 |
484
- | `Shift+Tab` | 승인 방식 (`⏵⏵ 자동` → `⏵ 위험만` → `⏸ 모두`) |
485
- | `Ctrl+O` | 작업 모드 (`종합` → `코드` → `계획` → …) |
486
- | `↑` `↓` | 지난 입력 이력 |
487
- | `Ctrl+C` | 답하는 중이면 그 답만 끊고, 빈 줄에서 두 번이면 끝냅니다 |
488
- | 일하는 중에 그냥 치고 `Enter` | 하던 일을 안 버리고 방향만 틉니다 — 다음 걸음부터 반영 |
489
-
490
- 한글 조합·붙여넣기·`Ctrl+A/E`·백스페이스는 전부 그대로 됩니다.
491
-
492
- > **자세히** — @파일 로 바로 붙이기 · 도중에 멈추기 · 멈추지 않고 방향만 틀기
493
- >
494
- > **[화면과 조작 읽기 →](docs/ko/interface.md#대화-중-명령)**
495
-
496
- ---
497
-
498
- ## 작업 모드
499
-
500
- 무슨 일을 하는 중인지에 따라 **줄 있는 도구와 추론 설정이 같이 바뀝니다.**
501
- `Shift+Tab` 으로 차례로 돌리거나, 이름을 그대로 치면 됩니다.
502
-
503
- | 모드 | 하는 | 파일을 고치나 | 추론 |
504
- |---|---|---|---|
505
- | `/auto` ◎ 종합 | **처음 값.** 말을 보고 알맞은 모드로 옮겨 간다 | 예 | 보통 (`save`) |
506
- | `/code` 코드 | 고치고 만든다 | 예 | 보통 (`save`) |
507
- | `/plan` ☰ 계획 | 먼저 계획만 세운다 | **아니오** | 깊게 (`deep`·high) |
508
- | `/architect` 설계 | 구조를 짠다 | **아니오** | 깊게 (`deep`·high) |
509
- | `/debug` ◉ 디버그 | 원인을 찾는다 | 예 | 깊게 · 단계 많이 (32) |
510
- | `/ask` 묻기 | 설명만 한다 | **아니오** | 얕게 (`low`) |
511
- | `/orchestrator` ❋ 총괄 | 큰 일을 쪼개서 | 예 | 단계 아주 많이 (40) |
512
-
513
- 읽기만 하는 모드에서는 `Write`·`Edit`·`Bash` 를 **모델에게 아예 보내지 않습니다.**
514
- "고치지 마세요" 라고 부탁하지 않습니다 — 모델은 부탁을 잊습니다. 없는 도구는 못 씁니다.
515
-
516
- `/mode` 헷갈리지 마세요. 둘은 다른 축입니다.
517
-
518
- - `/mode` **얼마나 물어보나** (auto · confirm · strict)
519
- - `/work` — **무슨 일을 하는 중인가** (위 일곱 가지)
520
-
521
- `/think` `/mode` 직접 고른 적이 있으면 선택이 우선합니다.
522
- 모드가 사람이 고른 값을 덮어쓰지 않습니다.
523
-
524
- > **자세히** 저절로 옮겨 가기 (종합 모드)
525
- >
526
- > **[화면과 조작 읽기 →](docs/ko/interface.md#작업-모드)**
527
-
528
- ---
529
-
530
- ## 쉬움 · 개발자
531
-
532
- 처음 사람에게 명령 스무 개를 들이밀면 아무것도 고릅니다.
533
- 그렇다고 기능을 잠그면 만해졌을 막힙니다. 그래서 **보이는 것만** 나눕니다.
534
-
535
- | | 쉬움 (기본) | 개발자 |
536
- |---|---|---|
537
- | `/help` 목록 | 자주 쓰는 것만 | 전부 |
538
- | 오류 문구 | 무엇을 하면 되는지 | 원래 문구 그대로 |
539
- | 안전 장치 | **똑같음** | **똑같음** |
540
-
541
- `/level 개발자` 바꾸면 설정에 남아 다음에 켤 때도 이어집니다.
542
-
543
- 중요한 가지입니다.
544
-
545
- - **감춘 것도 그대로 먹습니다.** 쉬움에서 `/think high` 쳐도 됩니다. 목록에 띄울 뿐입니다.
546
- - **초보라고 승인을 받지 않습니다.** 되돌리기·작업 범위·위험 명령 차단은 수준이 같습니다.
547
- 초보일수록 되돌릴 있어야 합니다.
548
-
549
- > **자세히** 입력칸 · 명령은 안 쳐도 됩니다 · 일하는 중에는 상자가 그대로 있습니다 · 왼쪽 그림도 같이 움직입니다 외 1개
550
- >
551
- > **[화면과 조작 읽기 →](docs/ko/interface.md#쉬움--개발자)**
552
-
553
- ---
554
-
555
- ## 도구
556
-
557
- 이름과 인자를 Claude Code 같게 맞췄습니다. 관례로 쓰인 스킬·명령이 그대로 먹습니다.
558
-
559
- | 도구 | 하는 |
560
- |---|---|
561
- | `Read` | 파일 읽기 ( 번호 · `offset`/`limit` 지원 · **엑셀은 CSV 로, hwpx·docx·pptx·PDF 는 글로 바꿔서**) |
562
- | `Write` | 파일 쓰기·덮어쓰기 (**여러 개는 `files` 배열로 번에**) |
563
- | `Append` | 파일 끝에 이어 붙이기 — **큰 파일을 나눠 쓰는 자리** |
564
- | `Edit` | 정확한 문자열 바꾸기 (`replace_all` · **여러 군데는 `edits` 배열로 한 번에**) |
565
- | `Move` | 파일·폴더 옮기기·이름 바꾸기 **구조를 바꾸는 자리** (`moves` 배열로 한 번에 · 되돌리기에 잡힘) |
566
- | `Glob` | 이름 패턴으로 파일 찾기 |
567
- | `Grep` | 내용 정규식 검색 |
568
- | `Bash` | 명령 실행 (**끝나지 않는 것은 `background: true`**) |
569
- | `Skill` | 스킬 본문 펼쳐 읽기 (스킬이 있을 때만 모델에게 보임) |
570
- | `WebFetch` | 웹 페이지 읽기 (읽기 전용 · `--offline` 이면 숨김) |
571
- | `Ask` | 갈림길에서 **사람에게 되묻기** — 고를 것을 주고 숫자 하나로 받는다 |
572
- | `Recall` | **지난 대화**에서 찾기 — "저번에 그거" 를 모델이 스스로 뒤진다 |
573
- | `Remember` | 대화가 끝나도 남길 것 한 줄 — 다음에 켤 때 처음부터 안다 |
574
- | `TodoWrite` | 할 일 목록 — 긴 일을 쪼개서 어디까지 했는지 화면에 띄움 |
575
- | `Outline` | 폴더의 **뼈대만** 보기 통째로 읽는 것보다 수십 분의 |
576
- | `Verify` | 만든 것이 **진짜 되는지** 확인 |
577
- | `Task` | 일의 덩이를 **따로 떨어진 창**에서 돌리기 |
578
- | `Jobs` | **뒤에서 도는 명령** 보기·읽기·끝내기 — `Bash` 의 `background` 와 짝 |
579
- | `Def` | 이름이 **어디 정의됐는지** 언어 서버가 깔려 있을 때만 보입니다 |
580
- | `Refs` | 이름을 **어디서 쓰는지** 전부언어 서버가 깔려 있을 때만 보입니다 |
581
-
582
- Claude Code 없는 것은 아홉입니다 — `Append` · `Move` · `Ask` · `Recall` ·
583
- `Remember` · `Outline` · `Verify` · `Task` · `Jobs`. 도구 하나가 스키마로 150~400토큰을 먹고
584
- 그게 **매 요청마다** 나가므로, 늘릴 때마다 검사에서 멈추게 뒀습니다
585
- (`test/loop.test.js`). 뒤의 넷은 그 값을 치르고도 넣을 만해서 넣은 것들이라,
586
- 아래에 왜인지를 적어 뒀습니다.
587
-
588
- > **자세히** — Outline · Verify · Task · Def · Refs · 끝나지 않는 명령은 뒤에서 외 9개
589
- >
590
- > **[도구 자세히 읽기 →](docs/ko/tools.md#도구)**
591
-
592
- ---
593
-
594
- ## 한글 문서와 엑셀
595
-
596
- **CP949 로 저장된 파일은 CP949 로 되돌려 씁니다.** 인코딩을 바꾸지 않습니다.
597
- 엑셀(`.xlsx`)은 CSV 로, 한글·워드·파워포인트(`.hwpx`/`.docx`/`.pptx`)
598
- **PDF** 글로 바꿔서 읽습니다 전부 읽기 전용입니다.
599
-
600
- PDF **못 읽은 쪽을 읽었다고 말합니다.** 스캔본·암호·글꼴 표가 없는 쪽은
601
- 글로 넘기지 않고 자리에 까닭을 적습니다 글은 「그런 내용이 없다」로
602
- 읽히기 때문입니다.
603
-
604
- 옛 형식(`.ppt`·`.doc`·`.xls`·`.rtf`)은 **이 PC 에 깔린 LibreOffice 를 빌려서**
605
- 읽습니다 `rg` 빌려 쓰는 것과 같은 원칙으로, 아무것도 설치하지 않습니다.
606
- 없으면 **없다고 박고 끝냅니다**(무엇이 없어서 하는지, 무엇을 하면 되는지,
607
- 그리고 「다시 열지 말라」까지). 끄려면 `DEEL_CONVERT=off`.
608
-
609
- > **자세히** — 인코딩 · 엑셀 · hwpx/docx/pptx · PDF · 변환기 빌려 쓰기
610
- >
611
- > **[한글 문서와 엑셀 읽기 →](docs/ko/documents.md#한글-문서와-엑셀)**
612
-
613
- ---
614
-
615
- ## 만든 웹을 그 자리에서 띄웁니다
616
-
617
- ```
618
- /preview
619
-
620
- ▶ 띄웠습니다 http://127.0.0.1:56801/
621
- 보여 주는 것 .
622
- 파일을 고치면 화면이 저절로 새로 뜹니다.
623
- 이 컴퓨터에서만 열립니다(127.0.0.1). 다른 PC 에서는 안 보입니다.
624
- 끄려면 /preview off · deel 끝내면 같이 꺼집니다.
625
- ```
626
-
627
- 브라우저가 같이 열립니다. `/preview 폴더` 자리를 정하고, `/preview off` 로 끕니다.
628
-
629
- **파일을 눌러 여는 것(`file://`)과 다릅니다.** `file://` 에서는 아래가 전부
630
- 막힙니다 그런데 오류는 콘솔에만 나오고 화면은 그냥 희어서, 만든 사람은 코드를
631
- 의심하며 시간을 씁니다. 진짜 HTTP 서버라 다 돕니다:
632
-
633
- | | `file://` | `/preview` |
634
- |---|---|---|
635
- | `<script type="module">` · `import` | 막힘 (CORS) | **됨** |
636
- | `fetch('./자료.json')` | 막힘 | **됨** |
637
- | `new Worker(...)` | 막힘 | **됨** |
638
- | `WebAssembly.compileStreaming` | 막힘 (형식) | **됨** |
639
- | 텍스처·`getImageData` | 캔버스 오염 | **됨** |
640
- | `.glb` / `.gltf` (Three.js) | 형식 없음 → 조용히 안 그려짐 | **됨** |
641
-
642
- 실제 크롬에서 이 일곱 가지를 돌려 **7/7** 을 확인했습니다.
643
-
644
- 라우터를 쓰는 앱(React Router 등)은 안쪽 주소에서 새로고침해도 첫 장이 나옵니다.
645
- 다만 확장자가 있는 요청(`app.js`)에는 절대 안 그럽니다 — 없는 스크립트에 HTML 을
646
- 돌려주면 `Unexpected token '<'` 로 죽는데, 그게 진짜 원인(파일 이름 오타)을 가립니다.
647
-
648
- ### 열어 주는 만큼만 엽니다
649
-
650
- 서버를 띄운다는 것은 내 디스크를 남에게 열어 주는 일입니다.
651
-
652
- - **`127.0.0.1` 에만** 묶습니다. `0.0.0.0` 은 아예 못 씁니다 — 같은 사무실 망에서
653
- 아무나 소스를 읽게 됩니다.
654
- - 포트는 **0**(커널이 것을 줍니다). 고정 포트는 남이 쓰던 것을 뺏습니다.
655
- - 경로는 작업 범위 밖으로 나갑니다. `../` · `%2e%2e` · 인코딩 · 절대 경로 ·
656
- 널바이트 · 심볼릭 링크 여덟 가지를 검사로 막아 뒀습니다.
657
- - **주기만 합니다.** `POST` · `PUT` · `DELETE` 405 거절합니다.
658
- - `deel` 끝내면 같이 꺼집니다.
659
-
660
- ## 스킬·플러그인
661
-
662
- **남의 스킬은 품고 다니지 않습니다.** 켜질 PC 훑어 있는 것을 그대로 씁니다.
663
-
664
- **다만 일하는 방법 일곱 가지는 품고 다닙니다.** 사내에서 새로 받은 PC 에는
665
- `~/.claude/skills` 플러그인도 없습니다. 거기서는 방법론이 0개라 모델이 매번
666
- 나름대로 했고, 시킨 것만 겨우 하고 끝나는 얄팍한 결과가 거기서 나왔습니다.
667
-
668
- | 스킬 | 언제 |
669
- |---|---|
670
- | `깊이있게-만들기` | 고도화·보고용·선포용최소치만 내고 끝내지 않게 |
671
- | `끝까지-하기` | 시킨 것이 여러 조각일 때. 빼먹은 것은 말하게 |
672
- | `차근차근-디버깅` | 재현 좁히기 원인 고치기 증명 |
673
- | `검사-먼저` | 고치기 전에 실패하는 검사부터 |
674
- | `찔러보기` | 되는지 모를 시간 정해 작게 찔러 보고 버리기 |
675
- | `코드-줄이기` | 동작은 그대로 두고 읽기 쉽게 |
676
- | `스스로-검토` | 됐다고 말하기 전에. 것까지 말하게 |
677
-
678
- 목록으로 늘 나가는 몫은 354토큰입니다(8k 창의 4%). 본문은 `Skill` 로 부를 때만 나갑니다.
679
- 같은 이름을 직접 만들면 그쪽이 이깁니다 품고 다니는 것이 제일 낮은 자리입니다.
680
-
681
- ```
682
- 품고 다님 (패키지 안) ← 제일 낮은 자리
683
- 프로젝트 ./.deel/skills ./.claude/skills ./.deel/commands ./.claude/commands
684
- 사용자 ~/.deel/skills ~/.claude/skills ~/.claude/commands
685
- 플러그인 ~/.claude/plugins/** ~/.deel/plugins/**
686
- ```
687
-
688
- Claude Code 와 같은 형식(`SKILL.md` + YAML 앞머리, `commands/*.md`, `$ARGUMENTS`)을 읽습니다.
689
-
690
- > **자세히** 3단계로 나눠 올립니다 · 플러그인 받아 오기 · 넣은 것
691
- >
692
- > **[늘려 쓰기 읽기 →](docs/ko/extend.md#스킬플러그인)**
693
-
694
- ---
695
-
696
- ## 추론 강도
697
-
698
- 에이전트 한 번의 대답은 모델을 여러 번 부릅니다. **부를 때마다 필요한 생각의 양이 다릅니다.**
699
- 전부 세게 두면 느리고, 전부 얕게 두면 엉뚱한 길로 갑니다.
700
-
701
- 기본은 **한 줄**입니다. 알고 싶은 것은 '지금 얼마나 생각하나' 이지 단계표가 아닙니다.
702
-
703
- ```
704
- $ /think
705
-
706
- 추론 강도 medium (첫 판단 medium · 이어가기 low · 막혔을 때 high)
707
- 세게 /think high 더 빠르게 /think low
708
- ```
709
-
710
- | 배분 | 성격 |
711
- |---|---|
712
- | `even` (균일) | 모든 단계 같은 강도 — 예측 가능한 대신 느림 |
713
- | `save` (절약, 기본) | 판단만 세게, 이어가기는 얕게 |
714
- | `deep` (깊게) | 전 단계 한 칸씩 위로 — 어려운 일에만 |
715
-
716
- 배분은 `/think 배분 절약` 정합니다. **강도와 배분은 다른 축이라 명령을 갈랐습니다**
717
- 전에는 `/think high` `/think save` 같은 이름으로 다른 것을 정해서,
718
- 화면을 봐도 지금 무엇이 무엇인지 읽히지 않았습니다.
719
-
720
- 단계표는 `/think 자세히` 로 뺐습니다(개발자 수준 기본).
721
-
722
- ```
723
- $ /think 자세히
724
-
725
- 추론 강도 medium (첫 판단 medium · 이어가기 low · 막혔을 때 high)
726
- 배분 절약 첫 판단만 세게, 이어가기는 얕게 대개 이게 낫습니다
727
-
728
- 단계 강도 출력상한 언제
729
- 첫 판단 · medium 15,549 무엇을 할지 정하는 자리
730
- 이어가기 ↓ low 13,605 도구 결과를 읽고 다음
731
- 막혔을 때 ↑ high 16,384 직전 도구가 오류를
732
-
733
- 출력 상한은 16,384 (모르는 값이라 기본값) 안에서 나눕니다 — /out
734
- 컨텍스트 40,960 · 지금 2,087
735
- ```
736
-
737
- 마지막에서 두 번째 줄이 있는 이유: **세 값이 다 같을 때 그게 고장인지 아닌지**
738
- 줄로 갈립니다. 아는 상한이 낮으면 셋이 같아지는 것이 맞습니다.
739
- 한동안 표는 줄이 `16,384` 였고, 그건 표가 뜻이 없다는 뜻이었습니다.
740
-
741
- > **자세히** 컨텍스트 길이는 모델에서 긁어옵니다 · /out · 잘린 도구 호출
742
- >
743
- > **[속도와 씀씀이 읽기 →](docs/ko/tuning.md#추론-강도)**
744
-
745
- ---
746
-
747
- ## 자동 압축
748
-
749
- 컨텍스트가 80% 차면 앞선 대화를 **요약해서 접고 계속 이어 갑니다.**
750
- 그냥 잘라내면 모델이 하던 일을 잊고, 파일을 다시 읽고, 이미 고친 곳을 고칩니다.
751
-
752
- ```
753
- ◱ 대화 44개를 요약으로 접었습니다 — 10,399 → 3,170 토큰 (70% 줄어듦)
754
- ```
755
-
756
- 요약은 목표 / 한 일 / 알아낸 것 / 정한 것 / 남은 일 다섯 항목으로 남습니다.
757
- 접을 때 **도구 호출과 그 결과가 갈라지지 않는 자리**를 골라 자릅니다 — 갈라지면 서버가 400 을 냅니다.
758
- 요약 요청이 실패하면 옛 방식(그냥 줄이기)으로 물러서고 멈추지 않습니다.
759
-
760
- `/compact` 로 직접 접을 수도 있습니다.
761
-
762
- ---
763
-
764
- ## 대화 이어하기
765
-
766
- 터미널을 실수로 닫거나 컴퓨터가 재부팅돼도 하던 대화를 그대로 이어 받습니다.
767
- 오간 내용은 **메시지 하나가 끝날 때마다 바로** `.deel/sessions/` 적히기 때문에,
768
- 도중에 죽어도 그 직전까지는 남습니다.
769
-
770
- ```
771
- $ deel sessions
772
-
773
- ── 이 폴더의 대화 ──────────────────────────────────────────────
774
- 20260824-090200 방금 1턴 devstral-small-2507
775
- 테스트 깨진 고쳐줘
776
- · 20260824-084500 2시간 전 2턴 qwen2.5-coder:7b
777
- src/a.js 로그를 logger 바꿔줘
778
- ```
779
-
780
- | 명령 | 하는 |
781
- |---|---|
782
- | `deel --continue` | 폴더에서 가장 최근 대화 이어하기 |
783
- | `deel --resume <id>` | 골라서 이어하기 |
784
- | `deel sessions` | 남아 있는 대화 목록 |
785
- | `deel sessions --rm <id>` | 하나 지우기 |
786
-
787
- 줄에 메시지 하나씩 쓰는 `jsonl` 이라, 쓰다가 전원이 나가도 마지막 줄만 잃습니다.
788
- 이어받은 대화는 도구 호출과 그 결과의 짝까지 그대로 살아 있어 바로 이어서 일할 수 있습니다.
789
- 30일이 지나고 최근 30개 밖인 것은 자동으로 정리합니다.
790
-
791
- 저장 위치는 작업 폴더의 `.deel/sessions/` 이고, `.gitignore` 에 `.deel/` 이 들어 있어
792
- 깃에 올라가지 않습니다.
793
-
794
- ---
795
-
796
- ## 밖에서 도구 붙이기 (MCP)
797
-
798
- 사내 위키 검색기, 이슈 트래커, DB 조회기 같은 것을 각 팀이 MCP 서버로 만들어 두면
799
- deel 그걸 **코드를 안 고치고** 도구로 씁니다.
800
-
801
- `.deel/mcp.json` 적습니다. Claude Code 설정을 그대로 복사해 붙일 수 있습니다:
802
-
803
- ```json
804
- { "mcpServers": { "사내위키": { "command": "node", "args": ["wiki-mcp.js"] } } }
805
- ```
806
-
807
- 모델에게는 `mcp__사내위키__검색` 이라는 이름으로 보입니다. `/mcp` 로 무엇이 붙었는지 봅니다.
808
-
809
- **의존성은 그대로 0 입니다.** stdio 규격은 자식 프로세스의 stdin/stdout 단위
810
- JSON-RPC 2.0 을 주고받는 것이 전부라, `child_process` 와 `JSON` 이면 됩니다. SDK 가
811
- 필요 없습니다.
812
-
813
- > **자세히** — 다만 이건 남의 프로그램입니다
814
- >
815
- > **[늘려 쓰기 읽기 →](docs/ko/extend.md#밖에서-도구-붙이기-mcp)**
816
-
817
- ---
818
-
819
- ## 에디터 안에서 쓰기 (ACP)
820
-
821
- 터미널을 하나 더 띄우게 하는 도구는 두 주쯤 뒤에 안 씁니다. 개발자는 하루 종일
822
- IDE 안에 있습니다. 그래서 **ACP**(Agent Client Protocol) 지킵니다 Zed ·
823
- JetBrains · Neovim · Emacs 가 **저쪽을 한 줄도 안 고치고** deel 을 붙입니다.
824
-
825
- 에디터 설정에 이 명령 하나만 적으면 됩니다.
826
-
827
- ```
828
- deel acp
829
- ```
830
-
831
- 에디터가 이걸 자식 프로세스로 띄우고, 표준입출력으로 줄 단위 JSON-RPC 2.0 을
832
- 주고받습니다. 사람이 직접 명령은 아닙니다.
833
-
834
- **붙으면 이렇게 됩니다.**
835
-
836
- | 에디터 쪽 | deel 쪽 |
837
- |---|---|
838
- | 답이 흘러나오는 자리 | 모델이 흘리는 · 생각 |
839
- | 도구 목록 (아이콘·상태) | `Read` 읽기, `Edit` 고치기, `Bash` 실행 — **갈래를 붙여** 보냅니다 |
840
- | 파일 링크 | 고친 파일의 **절대 경로**. 눌러서 그 자리로 갑니다 |
841
- | 승인 창 | deel 의 안전망이 그대로 에디터 창으로 뜹니다 (`이번만` · `앞으로 묻지 않기` · `안 함`) |
842
- | 모드 고르개 | deel 작업 모드 7개 (`종합` · `코드` · `계획` · `설계` · `디버그` · `묻기` · `총괄`) |
843
- | 멈춤 단추 | 도중에 닿습니다 — 답을 기다리는 중에도 |
844
- | 지난 대화 | 껐다 켜도 그대로 열립니다. 터미널과 **같은 자리**에 남아서, 에디터에서 하던 것을 `deel --resume` 으로 이어받는 것도 됩니다 |
845
-
846
- **의존성은 그대로 0 입니다.** MCP 같은 이유입니다 단위 JSON-RPC 2.0 이
847
- 전부라 SDK 필요 없습니다.
848
-
849
- > **자세히** 조용히 깨지는 자리들
850
- >
851
- > **[늘려 쓰기 읽기 →](docs/ko/extend.md#에디터-안에서-쓰기-acp)**
852
-
853
- ---
854
-
855
- ## 비밀이 새지 않게
856
-
857
- 사람이 열쇠를 붙여 넣는 일은 드뭅니다. 새는 자리는 거의 항상 **명령 출력**입니다.
858
-
859
- ```
860
- env OPENAI_API_KEY=sk-proj-…
861
- git remote -v https://사람:토큰@github.com/…
862
- curl -v > Authorization: Bearer eyJ…
863
- 검사 실패 로그 연결 문자열이 통째로
864
- ```
865
-
866
- 글은 모델에게 실려 가고, **동시에** `.deel/sessions/*.jsonl` 로 디스크에
867
- 적힙니다. 그 파일은 나중에 `/recall` 로 다시 읽히고 `deel pack` 에 딸려 갈 수도
868
- 있습니다. 한 번 새면 여러 벌이 됩니다.
869
-
870
- 그래서 도구 결과가 대화로 들어가는 **한 자리**에서 가립니다.
871
-
872
- ```
873
- Bash(env | grep API) 완료
874
- 비밀로 보이는 2군데가 대화에 들어갔습니다 (openai · 환경변수) — 모델에 가려서 보냈습니다
875
- ```
876
-
877
- 찾는 것: 사설키 블록 · OpenAI/Anthropic 열쇠 · GitHub 토큰 · Slack 토큰 ·
878
- AWS · Google · JWT · 주소에 박힌 열쇠 · `Authorization` 계열 헤더 ·
879
- 이름이 `…KEY`/`…TOKEN`/`…SECRET`/`…PASSWORD` 인 환경변수. 그리고 **설정에 든
880
- 게이트웨이 열쇠는 모양과 상관없이** 그건 짐작이 아니라 아는 값이니까요.
881
-
882
- ### 파일 내용은 일부러 안 가립니다
883
-
884
- 가리고 싶은 마음이 제일 드는 자리가 `.env` 인데, 거기를 가리면 이렇게 됩니다 —
885
- 모델이 가려진 글을 보고, 그걸 고쳐서 되돌려 씁니다. 그러면 진짜 열쇠가 있던
886
- 자리에 `«가림»` 이 적힙니다. **비밀을 지키려다 사람의 열쇠를 우리 손으로
887
- 지우는 셈입니다.**
888
-
889
- 그래서 파일 쪽은 가리는 대신 **알립니다.**
890
-
891
- ```
892
- Read(.env) 12줄
893
- ! 비밀로 보이는 값 3군데가 대화에 들어갔습니다 (환경변수)
894
- 파일 내용은 가리지 않습니다 (가리면 되돌려 쓸 때 지워집니다)
895
- ```
896
-
897
- 무엇을 못 막는지 분명히 말하는 편이, 막았다고 해 놓고 파일을 망가뜨리는 것보다
898
- 언제나 낫습니다. 어느 쪽이든 감사기록에 남습니다.
899
-
900
- ---
901
-
902
- ## 안전망
903
-
904
- 승인 프롬프트 대신 **되돌릴 있게** 만들었습니다. 기본 모드 `auto` 는 묻지 않고 알아서 합니다.
905
-
906
- | 장치 | 내용 |
907
- |---|---|
908
- | **되돌리기** | 파일을 고치기 전 항상 스냅샷. `/undo` 로 턴 단위 복구. **`Bash` 로 옮기고 지우는 것도 포함** |
909
- | **바뀐 자리 보기** | 고칠 때마다 바뀐 줄을 화면에. 이번 대화 전체는 `/diff` |
910
- | **작업 범위** | 시작한 폴더 밖은 모델이 시켜도 거부 |
911
- | **위험 명령 차단** | 되돌릴 수 없는 것만 (디스크 포맷, 재귀 삭제, `--force` 푸시 등) |
912
- | **재실행 금지** | 변경성 명령은 실패해도 다시 실행하지 않음 — 두 번 돌면 사고 |
913
- | **중단** | Ctrl+C 도중에 끊어도 대화가 성한 채로 남음 |
914
- | **헛돌기 차단** | 같은 도구가 같은 이유로 3번 실패하면 그 턴을 멈추고 왜인지 말함 |
915
- | **안 읽는 자리** | 남의 도구 살림과 deel 자신의 기록·설정(열쇠)은 거절 |
916
- | **감사 로그** | `.deel/audit.jsonl` 에 전부 기록 |
917
-
918
- | 모드 | 언제 물어보나 |
919
- |---|---|
920
- | `auto` (기본) | 물어봄. 되돌리기가 안전망 |
921
- | `confirm` | 되돌릴 없는 명령만 |
922
- | `strict` | 파일 변경·명령 전부 |
923
-
924
- 되돌리기 이력은 파일 내용을 통째로 담기 때문에 파일을 여러 번 고치면 금방 커집니다.
925
- 32MB 를 넘으면 **최근 50턴만 남기고** 오래된 것을 버립니다. 방금 한 일은 언제나
926
- 되돌릴 있고, 지금 이력이 얼마나 되는지는 `/status` 에서 봅니다.
927
-
928
- > **자세히** Bash 로 사라진 것도 되돌아갑니다 · 안 읽는 자리
929
- >
930
- > **[안전망과 사내 반입 읽기 →](docs/ko/safety.md#안전망)**
931
-
932
- ---
933
-
934
- ## 사내 반입
935
-
936
- 심사서와 소스를 zip 하나로 묶습니다.
937
-
938
- ```bash
939
- deel pack --out deel-반입.zip
940
- ```
941
-
942
- ```
943
- ── 반입 묶음 ───────────────────────────────────────────────────
944
- deel-반입.zip
945
- 94개 파일 · 509.6KB
946
-
947
- 의존성 0개
948
- 설치 스크립트 없음
949
- 외부 import 0건
950
- 네트워크 호출 3곳 (설정한 주소로만)
951
- 포트 열기 1곳 (/preview 만)
952
- ```
953
-
954
- zip 안에는 **사람이 읽을 장, 기계가 읽을 장**이 같이 들어갑니다.
955
- 반입 심사는 사람만 보는 절차가 아니기 때문입니다 보안팀은 SBOM 스캐너에
956
- 먹여 취약점 목록을 뽑고, 운영팀은 감사 사양을 보고 SIEM 수집 규칙을 짭니다.
957
-
958
- | 파일 | 무엇 |
959
- |---|---|
960
- | `반입심사서.txt` | 의존성 · 설치 스크립트 · **소스를 훑어 찾은 네트워크·외부 명령 호출 자리 전부**(파일:줄) · 나가는 길 세 갈래 · 파일별 SHA-256 |
961
- | `sbom.cdx.json` | **SBOM (CycloneDX 1.5).** 스캐너에 그대로 넣습니다. 파일마다 부품 하나에 SHA-256, 의존성은 **빈 배열로 명시** — 안 적어 낸 것과 없는 것은 다릅니다 |
962
- | `심사명세.json` | 통신 목록(갈래마다 언제·어디로·무엇이·막는법·소스 자리) · **감사기록 사양**(칸 이름과 뜻, 안 남기는 것) · 파일 해시 |
963
-
964
- ```bash
965
- deel audit # 사람이 읽는 심사서만 보기
966
- deel sbom # 기계가 읽는 장을 표준출력으로 (deel sbom | jq)
967
- deel sbom --out 심사.json # 파일로
968
- deel sbom --only sbom # SBOM 한 장만
969
- ```
970
-
971
- 셋 다 손으로 적지 않고 코드가 소스를 훑어서 만듭니다 — 손으로 적으면 언젠가
972
- 사실과 어긋나고, **어긋난 심사 서류는 없느니만 못합니다.** 담당자가 한 번 틀린
973
- 것을 발견하면 나머지도 안 믿습니다. 감사기록 사양만은 손으로 적혀 있어서,
974
- 그것이 진짜 기록과 어긋나지 않는지를 검사가 매번 대조합니다.
975
-
976
- > **자세히** 사내 게이트웨이 진단
977
- >
978
- > **[안전망과 사내 반입 읽기 →](docs/ko/safety.md#사내-반입)**
979
-
980
- ---
981
-
982
- ## 설정
983
-
984
- `~/.deel/config.json` 저장됩니다. 프로젝트 폴더에 `.deel/config.json` 있으면 그쪽이 우선입니다.
985
-
986
- > **자세히** 붙는 서버 · 환경변수 · 실행 옵션 · 프로젝트 규칙
987
- >
988
- > **[설정 읽기 →](docs/ko/config.md#설정)**
989
-
990
- ---
991
-
992
- ## 문제 해결
993
-
994
- | 증상 | 확인할 것 |
995
- |---|---|
996
- | `주소를 찾을 수 없습니다` | 주소 오타, DNS, 사내망 접속 여부 |
997
- | `연결이 거부되었습니다` | 서버가 꺼져 있거나 포트가 다름 |
998
- | `인증서 문제` | `set NODE_EXTRA_CA_CERTS=C:\경로\사내CA.pem` |
999
- | 프록시를 거쳐야 | `set HTTPS_PROXY=http://프록시:포트` (인증은 `http://user:pw@프록시:포트`). 첫 화면과 `/status` 에 `프록시 …` 가 뜨면 거치는 것. 안 거칠 곳은 `NO_PROXY=.corp.com,10.1.2.3`, 아예 끄려면 설정에 `"proxy": "none"` |
1000
- | 프록시가 407 을 줌 | 프록시 주소에 `user:pw@` 를 넣으세요. NTLM · Negotiate 만 받는 프록시는 못 씁니다 — 담당자에게 Basic 이나 인증 없는 주소를 문의 |
1001
- | 401 / 403 | 키가 틀렸거나 인증 헤더 형식이 다름 (4가지를 자동 시도합니다) |
1002
- | `허용되지 않은 주소입니다` | 자물쇠가 막은 것. 정상입니다 — `/model` 로 연결을 고르세요 |
1003
- | 도구 호출이 안 먹음 | `deel diagnose` 로 판정을 보세요. 작은 모델(1B~3B)은 자주 못 합니다 |
1004
- | 대답이 비어 있음 | 스트리밍을 무시하는 서버입니다. 한 번은 저절로 다시 부르고, 그래도 비면 이 대화에서는 스트리밍을 끕니다 |
1005
- | 파일이 중간에 끊김 | `/out` 으로 지금 상한을 보고 올리세요. 상한을 몰라 16,384 로 서 있을 수 있습니다 |
1006
- | `HTTP 400` 뜸 | 서버가 보낸 문장을 그대로 보여 줍니다. 길이 문제면 숫자를 읽어 저절로 맞춥니다 |
1007
- | `429` · `503` | 게이트웨이가 잠깐 막은 것입니다. 세 번까지 저절로 기다렸다 다시 부릅니다(`Retry-After` 를 지킵니다). 그래도 계속 뜨면 할당량을 보세요 |
1008
- | `deel scan` 이 0곳 | 로컬 서버가 꺼져 있거나 다른 포트 — `--ports` 로 지정 |
1009
-
1010
- ---
1011
-
1012
- ## 개발
1013
-
1014
- ```bash
1015
- npm test 전체 검증 (5,685항목)
1016
- npm run coverage 검사가 소스의 어디를 밟았는지
1017
- npm run verify 반입·통신 검증만
1018
- npm run bench 편집 성공률 측정
1019
- npm run demo 화면이 어떻게 보이는지 실제로 돌려 보기
1020
- npm run check 전 파일 문법 검사
1021
- ```
1022
-
1023
- 검증은 **가짜 게이트웨이**를 띄워서 합니다. 실제 모델 없이 규격 그대로
1024
- 루프·스트리밍·도구 실행·되돌리기·압축을 결정적으로 확인합니다.
1025
- zip 은 진짜 `unzip` 으로, tar 는 진짜 `tar` 가 만든 것을 읽혀 교차 확인합니다.
1026
-
1027
- `npm test` 는 파일을 하나씩 돌리고 **파일별 종료코드**를 표로 남깁니다.
1028
- 화면의 통과 표시가 아니라 종료코드가 CI 보는 값이기 때문입니다. 둘은
1029
- 갈라질 있습니다검사를 통과하고도 끝낼 죽으면 화면은 초록인데
1030
- 종료코드는 1 입니다. 실제로 윈도우에서 그렇게 한 번 놓쳤습니다.
1031
- 첫 실패에서 멈추지 않고 끝까지 돌기 때문에, 한 번 돌리면 전부 알 수 있습니다.
1032
-
1033
- ```
1034
- ────────────────────────────────────────────────────────────
1035
- 검사 파일 종료코드 통과 실패 시간
1036
- ────────────────────────────────────────────────────────────
1037
- smoke.js 0 20 0 0.2초
1038
- ✗ scan.test.js 1 19 0 0.2초
1039
- ────────────────────────────────────────────────────────────
1040
-
1041
- scan.test.js 종료코드 1
1042
- 검사는 전부 통과했는데 종료코드만 1 입니다 —
1043
- 끝낼 때 남은 핸들·처리 안 된 거절 때문입니다.
1044
- ```
1045
-
1046
- | 검증 | 항목 | 무엇을 |
1047
- |---|---|---|
1048
- | `smoke` | 20 | 도구·작업범위·되돌리기·감사로그 |
1049
- | `loop` | 16 | 에이전트 루프·스트리밍·도구 호출 |
1050
- | `guard` | 24 | **안 하는 자리** — 거부·모르는 도구·두 번 실행·범위 밖 |
1051
- | `network` | 30 | 정해진 자리 밖으로 새지 않는가 |
1052
- | `web` | 25 | 읽기가 읽기만 하는가 |
1053
- | `abort` · `steer` | 16 · 15 | Ctrl+C 끊어도 대화가 성한가 · 도중에 말이 다음 부름에 실리는가 |
1054
- | `parallel` | 23 | 읽기만 동시에 도는가 · 목록 |
1055
- | `cli` | 75 | **진짜 `deel` 띄워** 끝까지 돌려 본다 |
1056
- | `setup` | 42 | 실행 마법사 (가짜 TTY 사람처럼 입력) |
1057
- | `detect` | 66 | 주소 줄로 규격·인증을 짚어내는가 |
1058
- | `modes` · `route` | 89 · 33 | 작업 모드 · 종합에서 알맞은 모드로 옮겨 가는가 |
1059
- | `ctxsize` | 43 | 모델에 걸린 컨텍스트 길이를 긁어오는가 |
1060
- | `commands` · `commands-more` | 128 · 62 | 슬래시 명령 전부 |
1061
- | `ui` · `ui2` | 60 · 40 | 암호 가림·한글 폭·상태줄·대화 목록·엑셀→글 |
1062
- | `encoding` · `xlsx` | 68 · 72 | 한글 인코딩 판별 · 엑셀 읽기 |
1063
- | `compact` | 21 | 요약 압축·짝 안 깨짐·실패 시 물러섬 |
1064
- | `store` | 34 | 대화 저장·이어하기·중간에 죽어도 복구 |
1065
- | `scan` | 29 | 여러 런타임을 구분해 찾는가 |
1066
- | `plugins` | 38 | 플러그인 받기·묶기·ZIP/TAR |
1067
- | `no-bundle` | 12 | 배포 묶음에 남의 것이 안 섞였는가 · 검사 파일 위생 |
1068
- | `edit-bench` | 20건 | 편집 성공률 |
1069
-
1070
- > **자세히** 어디를 밟았는지 · 폴더 구조
1071
- >
1072
- > **[개발 읽기 →](docs/ko/develop.md#개발)**
1073
-
1074
- ---
1075
-
1076
- ## 릴리스 노트
1077
-
1078
- | | 무엇이 바뀌었나 |
1079
- |---|---|
1080
- | **[1.7.0](docs/ko/releases/1.7.md#170)** | 로컬은 그대로 두고, 말했을 때만 바깥으로 — 모드 셋 · 벤더 붙이기 · 자동 마스킹 · 돈 표시 |
1081
- | [1.6.3](docs/ko/releases/1.6.md#163) | 일이 되고 있는데 헛돈다고 끊던 자리 — 배열로 옮기면 무엇이 움직였는지가 사라졌다 |
1082
- | **[1.6.2](docs/ko/releases/1.6.md#162)** | 누르면 멈추고, 시킨 대로 하고, 안 끊긴다 — ESC · 되묻기 · 요청 누락 · 붙여넣기 접기 · 끊긴 자리 잇기 |
1083
- | **[1.6.1](docs/ko/releases/1.6.md#161)** | 헛도는 턴을 만들던 자리들 — 울타리가 `/dev/null` 까지 막던 것 · 옷 문서를 못 읽던 것 · 파일에서 그림이 사라지던 것 |
1084
- | **[1.6.0](docs/ko/releases/1.6.md#160)** | 사내망에서 안 되던 것들 — 프록시 · 429 · 윈도우 셸 · 5만 개 저장소 · PDF · 캡처 붙여넣기 · 에디터 이어하기 |
1085
- | **[1.5.8](docs/ko/releases/1.5.md#158)** | 5MB 문서를 919줄 중 8줄만 보던 것 · 정규식을 경로로 읽어 명령을 막던 것 |
1086
- | **[1.5.7](docs/ko/releases/1.5.md#157)** | 맥 한글 폴더에서 제 파일이 「범위 밖」이던 것 · 붙여넣기 · ESC |
1087
- | **[1.5.6](docs/ko/releases/1.5.md#156)** | 막히면 물어본다 — 글로 묻고 턴을 끝내는 대신에 |
1088
- | **[1.5.5](docs/ko/releases/1.5.md#155)** | 계획을 세우면 방이 찬다 — 「한 명뿐」은 고정이 아니라 버그였다 |
1089
- | [1.5.4](docs/ko/releases/1.5.md#154) | 방에 하루가 흐른다 — 아침·낮·노을·밤 · 벽시계 · 식은 커피 |
1090
- | [1.5.3](docs/ko/releases/1.5.md#153) | 맥에서 걸린 세 가지 — 줄바꿈 안내 · 사무실이 안 사라짐 · `/motion` 하나로 |
1091
- | [1.5.2](docs/ko/releases/1.5.md#152) | 적대적 리뷰가 남긴 나머지를 전부 정리했다 — 화면이 거짓말하던 자리들 |
1092
- | [1.5.1](docs/ko/releases/1.5.md#151) | 1.5.0 이 넣은 것 두 개가 망가진 채 나갔다. 그것을 고친다 |
1093
- | [1.5.0](docs/ko/releases/1.5.md#150) | 줄바꿈이 생겼고, 화면이 재미있어졌고, 그러면서 오히려 가벼워졌다 |
1094
- | [1.4.3](docs/ko/releases/1.4.md#143) | README 가 왜 다른지 말하고, 심사서의 빠진 한 줄을 채운다 |
1095
- | [1.4.2](docs/ko/releases/1.4.md#142) | 1.4.1 보안 수정 전에 나갔다 그걸 바로잡는 |
1096
- | [1.4.1](docs/ko/releases/1.4.md#141) | 기능 없이, 실제로 찾은 것만 고친다 윈도우 abort·ReDoS·XSS |
1097
- | [1.4.0](docs/ko/releases/1.4.md#140) | deel 얼굴을 갖고, 영어로도 말하고, 뜻까지 본다 — 열한 자리 |
1098
- | [1.3.0](docs/ko/releases/1.3.md#130) | 말 대신 증거, 터미널 대신 에디터 — 여섯 자리 |
1099
- | [1.2.0](docs/ko/releases/1.2.md#120) | 대화가 끊기지 않게 — 여섯 자리 |
1100
-
1101
- 무엇이 바뀌었는지는 **[릴리스 노트](docs/ko/releases.md)** 있습니다.
1102
-
1103
- ---
1104
-
1105
- ## 라이선스
1106
-
1107
- [MIT](LICENSE)
1
+ <div align="center">
2
+
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jysvai/deel-local-cli/main/docs/assets/hero-en-dark.svg">
5
+ <img alt="deel — stays on this machine" src="https://raw.githubusercontent.com/jysvai/deel-local-cli/main/docs/assets/hero-en-light.svg" width="620">
6
+ </picture>
7
+
8
+ ### A coding-agent CLI that runs on local models and private gateways
9
+
10
+ Zero dependencies · Node 20+ · Exactly one place your source can go
11
+
12
+ Vendor APIs connect too**only when you say so**
13
+
14
+ <br>
15
+
16
+ [![npm](https://img.shields.io/npm/v/deel-local-cli?logo=npm&logoColor=white&label=npm&color=cb3837)](https://www.npmjs.com/package/deel-local-cli)
17
+ [![downloads](https://img.shields.io/npm/dt/deel-local-cli?label=downloads&color=1a7f37)](https://www.npmjs.com/package/deel-local-cli)
18
+ [![node](https://img.shields.io/node/v/deel-local-cli?logo=nodedotjs&logoColor=white&label=node&color=5FA04E)](https://nodejs.org)
19
+ [![license](https://img.shields.io/npm/l/deel-local-cli?label=license&color=0969da)](LICENSE)
20
+
21
+ [![Node.js CI](https://img.shields.io/github/actions/workflow/status/jysvai/deel-local-cli/test.yml?branch=main&logo=github&logoColor=white&label=Node.js%20CI)](https://github.com/jysvai/deel-local-cli/actions/workflows/test.yml)
22
+ [![CodeQL](https://img.shields.io/github/actions/workflow/status/jysvai/deel-local-cli/codeql.yml?branch=main&logo=github&logoColor=white&label=CodeQL)](https://github.com/jysvai/deel-local-cli/actions/workflows/codeql.yml)
23
+ [![tests](https://img.shields.io/badge/tests-5%2C899%20passing-1a7f37?logo=checkmarx&logoColor=white)](docs/en/develop.md)
24
+
25
+ [![dependencies](https://img.shields.io/badge/dependencies-0-1a7f37)](https://www.npmjs.com/package/deel-local-cli?activeTab=dependencies)
26
+ [![ESM](https://img.shields.io/badge/ESM-Node%2020%2B-5FA04E?logo=javascript&logoColor=white)](package.json)
27
+ [![network](https://img.shields.io/badge/network-127.0.0.1%20only-1a7f37?logo=wireguard&logoColor=white)](#where-your-data-can-go)
28
+ [![telemetry](https://img.shields.io/badge/telemetry-none-1a7f37?logo=ghostery&logoColor=white)](#where-your-data-can-go)
29
+
30
+ **[한국어](README.ko.md)** · [Corporate review](#corporate-review-package) · [Troubleshooting](#troubleshooting) · [Full docs](docs/en/)
31
+
32
+ </div>
33
+
34
+ ---
35
+
36
+ ### The first thing you see answers the only question that matters
37
+
38
+ <picture>
39
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jysvai/deel-local-cli/main/docs/assets/shot-head-en-dark.svg">
40
+ <img alt="deel startup panel: model, where it sends, link capabilities, folder, approval mode" src="https://raw.githubusercontent.com/jysvai/deel-local-cli/main/docs/assets/shot-head-en-light.svg" width="900">
41
+ </picture>
42
+
43
+ **`sends to this machine 127.0.0.1 ← and nowhere else`.** Not in a policy document —
44
+ on screen, every time you start. The `⌂` in front stays in the status bar for the whole
45
+ session and turns into `↗` the moment traffic would leave. A real capture, not a mockup:
46
+ `node tools/shot.mjs` regenerates every image on this page from a live run.
47
+
48
+ <br>
49
+
50
+ Then you give it work, and it goes and does it:
51
+
52
+ <picture>
53
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jysvai/deel-local-cli/main/docs/assets/shot-chat-en-dark.svg">
54
+ <img alt="deel doing a task end to end: Grep, Read, Edit with an inline diff, and the file it wrote" src="https://raw.githubusercontent.com/jysvai/deel-local-cli/main/docs/assets/shot-chat-en-light.svg" width="900">
55
+ </picture>
56
+
57
+ Every number in that image is real — the tools ran against real files. Only the model is a
58
+ stub on `127.0.0.1`, so the capture is reproducible; the tool calls, the diff and the file
59
+ summary are what deel actually printed.
60
+
61
+ ---
62
+
63
+ ## 60 seconds
64
+
65
+ ```bash
66
+ npm i -g deel-local-cli # 0 dependencies, no install scripts
67
+ deel setup # point it at Ollama, LM Studio, or your gateway
68
+ deel # start working in the current folder
69
+ ```
70
+
71
+ No account, no sign-up, no telemetry. If you already run Ollama or LM Studio,
72
+ `deel setup` finds it — `deel scan` lists every local runtime and model on the machine.
73
+
74
+ ---
75
+
76
+ <details>
77
+ <summary><b>Contents</b> every section on this page</summary>
78
+
79
+ <br>
80
+
81
+ - [Why this exists](#why-this-exists)
82
+ - [What's different](#whats-different)
83
+ - [Quick start](#quick-start)
84
+ - [Where your data can go](#where-your-data-can-go)
85
+ - [Connecting a vendor API](#connecting-a-vendor-api)
86
+ - [Keys that expire (corporate gateways)](#keys-that-expire-corporate-gateways)
87
+ - [Multiple local runtimes](#multiple-local-runtimes)
88
+ - [Slash commands](#slash-commands)
89
+ - [Work modes](#work-modes)
90
+ - [Simple vs developer](#simple-vs-developer)
91
+ - [Tools](#tools)
92
+ - [Korean text and Excel](#korean-text-and-excel)
93
+ - [Serving what you built](#serving-what-you-built)
94
+ - [Skills and plugins](#skills-and-plugins)
95
+ - [Reasoning effort](#reasoning-effort)
96
+ - [Auto-compaction](#auto-compaction)
97
+ - [Resuming a conversation](#resuming-a-conversation)
98
+ - [Attaching tools from outside (MCP)](#attaching-tools-from-outside-mcp)
99
+ - [Inside your editor (ACP)](#inside-your-editor-acp)
100
+ - [Keeping secrets out of the conversation](#keeping-secrets-out-of-the-conversation)
101
+ - [Safety](#safety)
102
+ - [Corporate review package](#corporate-review-package)
103
+ - [Configuration](#configuration)
104
+ - [Troubleshooting](#troubleshooting)
105
+ - [Development](#development)
106
+ - [Release notes](#release-notes)
107
+
108
+ </details>
109
+
110
+ This page is the **summary**. Each section links to the detail behind it.
111
+
112
+ | Full docs | What is in there |
113
+ |---|---|
114
+ | [Models](docs/en/models.md) | Grade and window size · Korean-model presets · project detection |
115
+ | [The screen](docs/en/interface.md) | The input box · work modes · simple vs developer · what it asks about |
116
+ | [Tools in depth](docs/en/tools.md) | `Outline` · `Verify` · `Task` · `Jobs` · `Append` · `Def`/`Refs` · edit matching |
117
+ | [Korean documents and Excel](docs/en/documents.md) | hwpx/docx/pptx/**PDF** · encoding · Excel → CSV |
118
+ | [Extending](docs/en/extend.md) | Skills · plugins · MCP · ACP |
119
+ | [Speed and spend](docs/en/tuning.md) | Per-stage effort · the prefix cache · context length |
120
+ | [Safety and corporate review](docs/en/safety.md) | Undo · working scope · audit log · the review package |
121
+ | [Configuration](docs/en/config.md) · [Development](docs/en/develop.md) | Env vars · run flags · running the tests · folder layout |
122
+ | [Release notes](docs/en/releases.md) | [1.10.x](docs/en/releases/1.10.md) · [1.9.x](docs/en/releases/1.9.md) · [1.8.x](docs/en/releases/1.8.md) · [1.7.x](docs/en/releases/1.7.md) · [older](docs/en/releases.md) |
123
+
124
+ ---
125
+
126
+ ## Why this exists
127
+
128
+ When a corporate security policy blocks **unapproved software**, most coding-agent tools are
129
+ unusable: hundreds of transitive dependencies, scripts that run at install time, and no
130
+ one-line answer to "where does it send my code?"
131
+
132
+ deel is built to pass that review.
133
+
134
+ | | deel |
135
+ |---|---|
136
+ | External dependencies | **0** — Node built-ins only |
137
+ | Install scripts | **none** unzip and run |
138
+ | Where source can go | **one address** — the one you configured |
139
+ | Requirement | Node 20+ |
140
+
141
+ Verify it yourself:
142
+
143
+ ```bash
144
+ npm view deel-local-cli dependencies # {}
145
+ npm view deel-local-cli scripts # no install/postinstall
146
+ deel audit # full review sheet
147
+ ```
148
+
149
+ ---
150
+
151
+ ## What's different
152
+
153
+ A handful of coding agents can talk to a local model. Far fewer were
154
+ **redesigned inside for running locally.**
155
+
156
+ | | Other tools | deel |
157
+ |---|---|---|
158
+ | `/undo` | rolls back files only — the conversation still believes it happened | rewinds **the conversation too** |
159
+ | Long conversations | pay a cost cloud tools never feel, unchanged, locally | ordering designed so the prefix cache **survives** |
160
+ | Edits on small models | fail on a single whitespace mismatch | 20%→**100%** success, 0 wrong-location edits |
161
+ | Korean models | unknown until you've run them | known **in advance** from public docs |
162
+ | "Done" | says so even for what wasn't checked | `/evidence` / `/export` — **unproven items included** |
163
+ | MCP · ACP | need an SDK | `child_process` + `JSON`, nothing else |
164
+ | Compliance paperwork | hand-written, drifts from reality | **generated by scanning the source** |
165
+
166
+ <br>
167
+
168
+ #### `/undo` rewinds the conversation along with the files
169
+
170
+ Roll back only the files and the model still believes it just made that edit
171
+ it builds the next step on a premise that no longer holds, and nothing on
172
+ screen says otherwise. deel folds the messages back in lockstep with the
173
+ files. Folding can orphan a tool call, which the server answers with a 400,
174
+ so the same pass repairs the pairing (`repairToolPairs`).
175
+
176
+ #### Fixed the hidden reason local models get slower as a conversation grows
177
+
178
+ Ollama and llama.cpp only reuse computation when a request's prefix exactly
179
+ matches the last one change one character near the front and everything
180
+ after it, the whole conversation, gets recomputed. A cloud API never pays
181
+ this cost, so cloud-first tools have no reason to care; someone running
182
+ locally feels it compound every turn. deel pushes what can change per turn
183
+ (mode, pins) to the **end** of the prompt and sends Ollama `keep_alive: 60m`
184
+ so the front stays cached. The ordering is enforced by a test
185
+ (`test/cache.test.js`).
186
+
187
+ #### Edits actually succeed on small models
188
+
189
+ Small local models often can't reproduce the exact whitespace of the string
190
+ they're trying to edit. The internal benchmark (`npm run bench`) measured
191
+ 20% success for the old exact-match-only approach. The current approach
192
+ (stepped whitespace/indent tolerance) measures **100%** and both approaches
193
+ land at **0** wrong-location edits. When it's ambiguous, it says so instead
194
+ of guessing.
195
+
196
+ #### Korean models are known before you've ever run them
197
+
198
+ EXAONE, HyperCLOVA X, Kanana, Midm, and Solar get whatever's verifiable from
199
+ public documentation (e.g., whether a model is a reasoning model) applied
200
+ before the first prompt. Other tools meet these models cold, and it takes a
201
+ dozen-plus turns of trial and error before anyone learns their quirks.
202
+
203
+ #### "Done" comes with a receipt, not just a claim
204
+
205
+ `/evidence` and `/export` record what wasn't verified alongside what was —
206
+ because the moment an AI coding tool is most likely to mislead someone is
207
+ exactly the moment it confidently says "done." `/export` is a self-contained
208
+ HTML file with zero outbound links, so it opens anywhere, including an
209
+ air-gapped network.
210
+
211
+ #### MCP and ACP, with no SDK
212
+
213
+ Both the Model Context Protocol and the Agent Client Protocol are just
214
+ newline-delimited JSON-RPC 2.0 over stdio. deel implements both with nothing
215
+ but `child_process` and `JSON` — proof that zero dependencies isn't a
216
+ capability given up, it's a capability that was never needed.
217
+
218
+ #### Compliance paperwork it doesn't hand-write
219
+
220
+ The import-review report, SBOM, and audit spec that `deel pack` produces are
221
+ generated **by scanning the actual source**, not typed by a person.
222
+ Hand-written paperwork eventually drifts from reality, and the moment a
223
+ reviewer catches one drifted claim, they stop trusting the rest of it.
224
+
225
+ ---
226
+
227
+ ## Quick start
228
+
229
+ ### The screen speaks your language
230
+
231
+ deel is written in Korean — the code, the function names, the comments. That part stays.
232
+ What you see on screen does not have to. Four screen languages ship: **한국어 · English ·
233
+ 日本語 · 中文**.
234
+
235
+ > **How this is kept honest:** `/lang` counting the table is not enough — it can only count
236
+ > strings that made it *into* the table, and for a long time the tool result summaries and the
237
+ > thinking indicator never did. So a test starts deel in each language and reads the screen:
238
+ > `test/langleak.test.js` walks seven screens and fails if a Korean character shows up on an
239
+ > English one. It also fails on `1 files`, and on a stray `·` left dangling at the end of a line.
240
+
241
+ ```bash
242
+ DEEL_LANG=en deel # this run only (also ja, zh)
243
+ /lang en # and remember it
244
+ /lang ja # 日本語
245
+ /lang zh # 中文
246
+ /lang # how much is translated so far
247
+ ```
248
+
249
+ Nothing ever comes through blank. A line that has not been translated falls back to English
250
+ first and Korean secondso a Japanese or Chinese screen degrades to English, not to Korean —
251
+ and `/lang` prints exactly how many strings are covered.
252
+
253
+ What the model reads follows the same switch. Set it to English and the rules, the mode
254
+ instructions, and the tool descriptions all go out in English — so the model answers you in
255
+ English instead of Korean. That side is cheaper, too: the part of the window that ships on every
256
+ single request drops from about 4,900 tokens to about 3,450 — on a 32k model, from 15% of the
257
+ window to 10.5%.
258
+
259
+ Tool and argument names are ASCII in every language — `Read(file_path)`, `Task(purpose)`.
260
+ Those are identifiers, not prose, and several vendors reject a non-ASCII name outright.
261
+ The Korean names some models learned earlier are still accepted on the way *in*, so a model
262
+ that sends `목적` instead of `purpose` still gets through.
263
+
264
+ ### Install
265
+
266
+ ```bash
267
+ npm install -g deel-local-cli
268
+ ```
269
+
270
+ Or skip installing entirely — there is no `npm install` step:
271
+
272
+ ```bash
273
+ git clone https://github.com/jysvai/deel-local-cli
274
+ node deel-local-cli/bin/deel.js
275
+ ```
276
+
277
+ > **Note** do not run `npm install` in your home directory. A `node_modules` there makes every
278
+ > later npm command scan it and report warnings about unrelated packages. Use `-g` or `npx`.
279
+
280
+ ### Point it at a model
281
+
282
+ Scan this machine and pick one:
283
+
284
+ ```bash
285
+ deel scan --pick
286
+ ```
287
+
288
+ Or enter an address directly (use this for a corporate gateway):
289
+
290
+ ```bash
291
+ deel setup
292
+ ```
293
+
294
+ ### Start
295
+
296
+ Run `deel` in the folder you want to work in. **That folder becomes the scope — files outside it
297
+ cannot be read or written.**
298
+
299
+ ```bash
300
+ cd C:\work\myproject
301
+ deel
302
+ ```
303
+
304
+ ---
305
+
306
+ ## Where your data can go
307
+
308
+ A coding agent ships your whole source to a model. **The address is everything.**
309
+ Rather than promising in prose, the code enforces it: `src/safety/network.js` checks every request
310
+ and never builds one for an address that is not on the allow-list.
311
+
312
+ ```
313
+ [A] Model gateway ────── the only path your source travels
314
+ One address, set in `setup`. Switching models closes the previous one.
315
+
316
+ [B] Web read (WebFetch) ─ receive-only
317
+ GET only, zero-byte body. Private/loopback addresses refused. Every visit logged.
318
+
319
+ [C] Plugin fetch ─────── open only while /plugin install runs
320
+
321
+ [D] MCP servers ──────── a separate child process, someone else's program
322
+ Only starts if a human writes it into .deel/mcp.json. Off by default.
323
+ ```
324
+
325
+ A, B, and C are requests deel makes itself, so each one can be filtered.
326
+ **D is different** — an MCP server is its own process; there is no way to see
327
+ what sockets it opens from the outside. So under `--offline`, instead of
328
+ filtering its requests, deel **never starts the server at all** — it doesn't
329
+ claim to have blocked what it can't actually see.
330
+
331
+ Pass `--offline` and **B, C, and D are all closed** — traffic stays on this machine.
332
+
333
+ ```bash
334
+ deel --offline
335
+ ```
336
+
337
+ The destination is printed at the top of every session:
338
+
339
+ ```
340
+ deel 1.10.0 ⌂ inside
341
+ Sends to this machine 127.0.0.1:11434 ← nowhere else
342
+ ```
343
+
344
+ ### Three run modes
345
+
346
+ Through 1.6 the only lock was `--offline`, and **the default was open**. One
347
+ line in `.deel/config.json` pointing outside was enough. The screen did show
348
+ `↗`, but that is a *notice*, not a lock.
349
+
350
+ | Mode | How | On an external address |
351
+ |---|---|---|
352
+ | `⌂ inside` | `deel` (default) | **Asks.** Say yes once and that connection stops asking |
353
+ | `↗ outside` | `deel online` · `--online` | Does not ask |
354
+ | `⛊ sealed` | `deel offline` · `--offline` | Ignores even remembered permission (strongest) |
355
+
356
+ **Both the address and the permission are required.** Changing the address
357
+ alone does not get you out.
358
+
359
+ Local and intranet ranges (`127.x` · `10.x` · `192.168.x` · `172.16-31.x`) pass
360
+ in all three modes `offline` does not mean "no internet," it means "nothing
361
+ leaves the company."
362
+
363
+ Nothing is collected or transmitted. No telemetry, no usage stats, no crash reporting.
364
+ Conversation history, undo snapshots and config live only in `.deel/` inside your working folder.
365
+
366
+ > Verified by 159 checks in `npm test` (network + web + mcp), including bringing up a real
367
+ > server and confirming that **not a single request reaches it** when it is not allow-listed,
368
+ > and that an MCP server **never starts** under `--offline`.
369
+
370
+ ---
371
+
372
+ ## Connecting a vendor API
373
+
374
+ Local models are the default and that does not change. But "we have no GPU
375
+ in-house" and "just this one task on a bigger model" are real situations, so
376
+ vendor APIs can connect. **The modes above guard that door.**
377
+
378
+ ```bash
379
+ deel setup
380
+ ```
381
+
382
+ Instead of asking for a URL, it asks **where you're connecting**.
383
+
384
+ ```
385
+ 1. I only have a key — I'll figure out where it goes 1 blank
386
+ 2. Enter an address (corporate gateway · local) 2 blanks
387
+ 3. OpenAI (GPT) 1 blank
388
+ 4. Anthropic (Claude) 1 blank
389
+ 5. Google (Gemini) 1 blank
390
+ 6. AWS Bedrock 2 blanks
391
+ ```
392
+
393
+ Option 1 is the point — the key prefix decides which single vendor is asked.
394
+
395
+ ```
396
+ sk-ant-api03-••••
397
+ Looks like an Anthropic (Claude) key. (the key starts with sk-ant-)
398
+ It is not thrown at every vendor in turn.
399
+ ```
400
+
401
+ Probing vendors one by one would send an Anthropic key to OpenAI's server and
402
+ then to Google's. You get a 401 and stop — but **the key has already left.**
403
+ So an unrecognized key is never guessed at; you are asked.
404
+
405
+ Bedrock asks for a region five including Seoul (`ap-northeast-2`), plus
406
+ "enter it yourself." Claude has a different wire shape, absorbed in six places
407
+ ([1.7.0 release notes](docs/en/releases/1.7.md#170)).
408
+
409
+ ### Going outside masks secrets in file contents too
410
+
411
+ While everything stayed local, text read from files was deliberately **not**
412
+ masked: mask it and the model writes the mask back into the file, destroying
413
+ your real key.
414
+
415
+ Going outside flips that trade. One `Read` puts your whole `.env` into someone
416
+ else's server log, and that cannot be undone. The other side is now handled
417
+ elsewhere `Write`, `Append` and `Edit` refuse to write a mask back into a file.
418
+
419
+ ### You can see what it costs
420
+
421
+ ```
422
+ ❯ ─ 12.4s · 3 tools · ↑8.2k ↓1.1k · $0.0271
423
+ ```
424
+
425
+ **There is no built-in price table.** Prices change whenever a vendor decides,
426
+ and a table baked into source would have the tool confidently printing wrong
427
+ amounts six months later. Write them in `.deel/config.json` dollars per
428
+ million tokens:
429
+
430
+ ```json
431
+ "pricing": { "claude-opus-4-6": { "input": 0, "output": 0, "asOf": "2026-09-01" } }
432
+ ```
433
+
434
+ The amount is shown with **where it came from and as of when**, and after six
435
+ months it is marked stale. Unknown means nothing is printeda local-only
436
+ session never sees money at all.
437
+
438
+ ---
439
+
440
+ ## Keys that expire (corporate gateways)
441
+
442
+ Corporate gateways do not hand out a fixed key. They hand out a one-hour token, behind a
443
+ corporate login. Pasting one in works until lunch, and then you get `HTTP 401` — a message
444
+ that **does not distinguish "wrong key" from "old key."** People go re-issue a key that was
445
+ never the problem.
446
+
447
+ So write down *how to get a key* instead of the key:
448
+
449
+ ```json
450
+ "authCommand": {
451
+ "command": "az account get-access-token --resource api://ai-gw --query accessToken -o tsv",
452
+ "ttl": 3600
453
+ }
454
+ ```
455
+
456
+ It runs right before a request, keeps the result in memory only, and fetches a fresh one a
457
+ minute before expiry a token alive when the request left and dead when it arrived is
458
+ exactly that 401. On a 401 it fetches once more and retries **once**; a second 401 means you
459
+ genuinely lack access.
460
+
461
+ | | |
462
+ |---|---|
463
+ | You write the path | Nothing is auto-detected. Guessing at `az` on your PATH would mean you no longer know when this program runs what |
464
+ | Separate process | Never `import`ed code inside our process would see other keys and the conversation |
465
+ | Asked once per session | Not once per fetch. Three prompts and people just press the key |
466
+ | Not while sealed | An `--offline` session does not go out to a login portal |
467
+ | Never written to disk | Memory only, for the life of the session |
468
+ | Banner output rejected | `Logged in as …` followed by a token gets a 400 from the gateway, indistinguishable on screen from a wrong key. The first line is shown back so you know to add `--query` |
469
+
470
+ `/status` says `Key store fetched · 52 min left` — not "stored", because we are not holding
471
+ it. An organisation can set the same block in the [managed policy](docs/en/config.md) file,
472
+ where it overrides the user's config and is never asked about.
473
+
474
+ ---
475
+
476
+ ## Multiple local runtimes
477
+
478
+ People rarely run just one. `deel scan` knocks on 13 known ports concurrently and identifies
479
+ each runtime from its **response**, not its port number — Ollama by `/api/version`,
480
+ LM Studio by `/api/v0/models`, llama.cpp by `/props`. Unrecognised ones are marked as a guess.
481
+
482
+ ```
483
+ $ deel scan
484
+
485
+ found 3
486
+
487
+ Ollama 127.0.0.1:11434 Ollama API 36ms
488
+ · qwen2.5-coder:7b 7B · 4.4GB
489
+ · llama3.2:1b 1B · 1.2GB
490
+ LM Studio 127.0.0.1:1234 OpenAI-compat 7ms
491
+ · devstral-small-2507
492
+ llama.cpp 127.0.0.1:8080 OpenAI-compat 7ms
493
+ · gemma-3-4b-it
494
+
495
+ Recommended Ollama · qwen2.5-coder:7b
496
+ ```
497
+
498
+ | Command | What it does |
499
+ |---|---|
500
+ | `deel scan` | Show what is running |
501
+ | `deel scan --pick` | Choose one from the list |
502
+ | `deel scan --save` | Register everything found |
503
+ | `deel scan --ports 9000,9100` | Extra ports to probe |
504
+ | `deel scan --host <addr>` | Defaults to `127.0.0.1` |
505
+
506
+ Switch with `/model` mid-conversation **the conversation carries over.**
507
+
508
+ > **More** It adapts to whatever model is attached · Korean models are known before they are experienced · Small windows get a smaller fixed share · On startup it reads what kind of project this folder is
509
+ >
510
+ > **[Models read →](docs/en/models.md#multiple-local-runtimes)**
511
+
512
+ ---
513
+
514
+ ## Slash commands
515
+
516
+ Names follow Claude Code / Codex conventions.
517
+
518
+ | Command | What it does |
519
+ |---|---|
520
+ | `/help` | Command list |
521
+ | `/lang [ko\|en] [prompt lang]` | Screen language. **The prompt language is a separate axis** — `/lang en ko` instructs the model in Korean while answering you in English. Korean screen + English prompt cuts the 8k fixed share by 23% |
522
+ | `/keys` | Press keys to see what your terminal actually sends — for when new lines will not work |
523
+ | `/bell [on\|off]` | Ring and set the window title when a turn ends, or when deel needs an answer |
524
+ | `/consult <profile> <question>` | Ask a second model one question. Your current model stays put |
525
+ | `/export` | This conversation as a **one-page HTML report** — asked, changed, verified. Self-contained, opens on any network |
526
+ | `/lsp [on\|off]` | Language servers — what is installed, and whether `Def`/`Refs` are available. `off` turns post-edit diagnostics off only |
527
+ | `/context` | What is consuming the context window |
528
+ | `/ctx [auto\|number]` | Context **length** — re-read it off the model, or set it yourself |
529
+ | `/grade [small\|medium\|large\|auto]` | Model **grade** — how much it does on its own. A different axis from `/ctx` |
530
+ | `/out [number\|auto]` | Cap on a **single reply** — raise it when large files get cut |
531
+ | `/compact` | Summarise and fold older turns |
532
+ | `/clear` | Clear the conversation (keeps link and rules) |
533
+ | `/thread [new\|fork\|close\|n]` | Conversation threads side work in its own context. Link and undo stay shared |
534
+ | `/learned [clear]` | What deel has picked up on its own — commands that work here, this model's habits |
535
+ | `/pin <text>` | Pin a line folding and compaction **cannot reach it** |
536
+ | `/evidence [file]` | Evidence — what changed, and what proves it. **What is unproven is listed too** |
537
+ | `/commit [all\|preview\|title]` | Commits only what this session changed; message from the diff and the evidence. **Never pushes** |
538
+ | `/model` | Switch connection / model |
539
+ | `/model card` | Model card what this model has actually done here, and what deel changed because of it |
540
+ | `/think <level>` | Reasoning level (`off·low·medium·high·max`) |
541
+ | `/think profile <name>` | Per-stage profile (`even·save·deep`) |
542
+ | `/think detail` | Stage table — which stage runs at which level and cap |
543
+ | `/mode <mode>` | Approval policy — how much it asks (`auto` · `confirm` · `strict`) |
544
+ | `/work [mode]` | Work mode — what kind of work you are doing |
545
+ | `/auto` | Hand the wheel back it picks the mode from what you type |
546
+ | `/code` `/plan` `/architect` `/debug` `/ask` `/orchestrator` | Switch work mode directly (pins it) |
547
+ | `/level [level]` | How much to show (`simple` · `developer`) |
548
+ | `/motion [plain\|knight\|animal\|office\|off]` | What animates while it works — takes effect at once, and is saved |
549
+ | `/undo [turns]` | Revert file changes |
550
+ | `/diff [file]` | Files changed this session, and the changed lines |
551
+ | `/preview [folder\|file\|off]` | Serve what you built, right here — a browser opens with it |
552
+ | `/tools` | Available tools |
553
+ | `/skills [query\|all\|off]` | Browse, search, load skills |
554
+ | `/plugin [install\|remove\|pack]` | Manage plugins |
555
+ | `/cost` | Session usage |
556
+ | `/status` | Connection status |
557
+ | `/scan [save]` | Sweep this machine for local model servers (`save` registers them) |
558
+ | `/sessions` | Past conversations in this folder |
559
+ | `/recall <text>` | Search past conversations **by content** |
560
+ | `/memory` | What persists across sessions — view, add, delete |
561
+ | `/mcp` | Externally attached tools (MCP servers) |
562
+ | `/init` | Create a `DEEL.md` rules file |
563
+ | `/exit` | Quit |
564
+
565
+ Discovered plugin commands are invoked as `/<plugin>:<name>`, with `$ARGUMENTS` substituted.
566
+
567
+ `/scan` and `/sessions` work without leaving the session. If you just started another local
568
+ server or loaded a different model, `/scan save` then `/model` switches over without losing
569
+ the conversation.
570
+
571
+ **Without typing**
572
+
573
+ | Key | What it does |
574
+ |---|---|
575
+ | `Tab` | Completes the `/` command you are typing. Candidates appear under the box as you type |
576
+ | `Shift+Tab` | Approval policy (`⏵⏵ auto` `⏵ risky only` → `⏸ everything`) |
577
+ | `Ctrl+O` | Work mode (`Auto` `Code` `Plan` …) |
578
+ | `↑` `↓` | Input history |
579
+ | `Ctrl+C` | Stops the answer in progress; twice on an empty line quits |
580
+ | Typing while it works, then `Enter` | Steers without throwing anything away takes effect from the next step |
581
+
582
+ Korean IME composition, paste, `Ctrl+A/E` and backspace all keep working.
583
+
584
+ > **More** Attaching a file with @ · Interrupting · Steering without stopping
585
+ >
586
+ > **[The screen read →](docs/en/interface.md#slash-commands)**
587
+
588
+ ---
589
+
590
+ ## Work modes
591
+
592
+ What you are working on changes **which tools the model is given and how hard it thinks.**
593
+ Cycle with `Shift+Tab`, or type the name.
594
+
595
+ | Mode | For | Can edit files | Reasoning |
596
+ |---|---|---|---|
597
+ | `/auto` Auto | **Default.** Reads your message and switches for you | Yes | Normal (`save`) |
598
+ | `/code` Code | Writing and fixing | Yes | Normal (`save`) |
599
+ | `/plan` ☰ Plan | Planning first | **No** | Deep (`deep`·high) |
600
+ | `/architect` Architect | Shaping structure | **No** | Deep (`deep`·high) |
601
+ | `/debug` Debug | Finding causes | Yes | Deep, more steps (32) |
602
+ | `/ask` ◇ Ask | Explaining only | **No** | Shallow (`low`) |
603
+ | `/orchestrator` ❋ Orchestrator | Breaking up large work | Yes | Many steps (40) |
604
+
605
+ In read-only modes, `Write`, `Edit` and `Bash` are **never sent to the model at all.**
606
+ It is not asked politely not to edit models forget requests. A tool that isn't there can't be used.
607
+
608
+ Don't confuse this with `/mode`. They are separate axes:
609
+
610
+ - `/mode` — **how much it asks you** (auto · confirm · strict)
611
+ - `/work` — **what kind of work you are doing** (the seven above)
612
+
613
+ If you have explicitly set `/think` or `/mode`, your choice wins. A work mode never
614
+ overrides something a person chose.
615
+
616
+ > **More** — Switching by itself (Auto mode)
617
+ >
618
+ > **[The screen read →](docs/en/interface.md#work-modes)**
619
+
620
+ ---
621
+
622
+ ## Simple vs developer
623
+
624
+ Twenty commands on first launch means nothing gets chosen. Locking features away means
625
+ hitting a wall later. So only **what is shown** differs.
626
+
627
+ | | Simple (default) | Developer |
628
+ |---|---|---|
629
+ | `/help` listing | Common commands only | Everything |
630
+ | Error messages | What to do about it | The original text |
631
+ | Safety | **Identical** | **Identical** |
632
+
633
+ `/level developer` is saved to config and persists across sessions.
634
+
635
+ Two things matter here:
636
+
637
+ - **Hidden commands still work.** `/think high` works in simple mode. It just isn't listed.
638
+ - **Beginners do not get fewer safeguards.** Undo, workspace scope and dangerous-command
639
+ blocking are identical. A beginner needs the undo more, not less.
640
+
641
+ > **More** — The input box · You don't have to type the whole command · The box stays while it works · The picture on the left moves too and 1 more
642
+ >
643
+ > **[The screen read →](docs/en/interface.md#simple-vs-developer)**
644
+
645
+ ---
646
+
647
+ ## Tools
648
+
649
+ Names and arguments match Claude Code, so skills written for that convention work unchanged.
650
+
651
+ | Tool | What it does |
652
+ |---|---|
653
+ | `Read` | Read a file (line numbers, `offset`/`limit`, **Excel as CSV, hwpx/docx/pptx and PDF as text**) |
654
+ | `Write` | Write / overwrite a file (**several at once via the `files` array**) |
655
+ | `Append` | Append to the end of a file **how large files get written in pieces** |
656
+ | `Edit` | Replace an exact string (`replace_all`; **several sites at once via the `edits` array**) |
657
+ | `Move` | Move / rename files and folders — **how you restructure** (`moves` array; covered by undo) |
658
+ | `Glob` | Find files by name pattern |
659
+ | `Grep` | Regex search file contents |
660
+ | `Bash` | Run a command (**`background: true` for anything that does not finish**) |
661
+ | `Skill` | Expand a skill body (shown to the model only when skills exist) |
662
+ | `WebFetch` | Read a web page (read-only; hidden under `--offline`) |
663
+ | `Ask` | **Ask you back** at a fork — offers the choices, takes a single number |
664
+ | `Recall` | Search **past conversations** the model digs up "that thing last time" itself |
665
+ | `Remember` | One line that outlives the session — known from the start next time |
666
+ | `TodoWrite` | Checklist breaks long work into steps and shows progress |
667
+ | `Outline` | See a folder's **skeleton only** — tens of times cheaper than reading it whole |
668
+ | `Verify` | Check that what was built **actually works** |
669
+ | `Task` | Run one chunk of a big job in a **separate context** |
670
+ | `Jobs` | Inspect, read and stop **background commands** the other half of `Bash`'s `background` |
671
+ | `Def` | **Where a name is defined** only shown when a language server is installed |
672
+ | `Refs` | **Every place a name is used** only shown when a language server is installed |
673
+
674
+ Nine tools here are not in Claude Code `Append`, `Move`, `Ask`, `Recall`, `Remember`,
675
+ `Outline`, `Verify`, `Task`, `Jobs`. Each tool costs 150-400 tokens of schema on **every request**,
676
+ so a test stops you every time the list grows (`test/loop.test.js`). The last four earned
677
+ their cost; here is why.
678
+
679
+ > **More** Outline · Verify · Task · Def · Refs · Commands that never finish and 9 more
680
+ >
681
+ > **[Tools in depth read →](docs/en/tools.md#tools)**
682
+
683
+ ---
684
+
685
+ ## Korean text and Excel
686
+
687
+ **A file saved as CP949 is written back as CP949.** The encoding is never changed.
688
+ Excel (`.xlsx`) is read as CSV read-only.
689
+
690
+ Old formats (`.ppt`, `.doc`, `.xls`, `.rtf`) are read by **borrowing the LibreOffice already
691
+ on this machine** — the same terms on which deel borrows `rg`, and nothing is ever installed.
692
+ With no converter it **says so definitively and stops**: what is missing, what you can do about
693
+ it, and not to open the file again. Turn it off with `DEEL_CONVERT=off`.
694
+
695
+ > **More** — Encoding · Excel · borrowing a converter
696
+ >
697
+ > **[Korean documents and Excel read →](docs/en/documents.md#korean-text-and-excel)**
698
+
699
+ ---
700
+
701
+ ## Serving what you built
702
+
703
+ ```
704
+ /preview
705
+
706
+ Serving http://127.0.0.1:56801/
707
+ showing .
708
+ Edit a file and the page reloads by itself.
709
+ Only this machine can open it (127.0.0.1). No other PC can see it.
710
+ Stop with /preview off · it shuts down when deel exits.
711
+ ```
712
+
713
+ A browser opens with it. `/preview <folder>` picks what to serve, `/preview off` stops it.
714
+
715
+ **This is not the same as double-clicking the file (`file://`).** Under `file://` everything
716
+ below is blocked and the error only shows up in the console while the page stays blank, so
717
+ you end up suspecting your own code. This is a real HTTP server, so it all works:
718
+
719
+ | | `file://` | `/preview` |
720
+ |---|---|---|
721
+ | `<script type="module">` · `import` | blocked (CORS) | **works** |
722
+ | `fetch('./data.json')` | blocked | **works** |
723
+ | `new Worker(...)` | blocked | **works** |
724
+ | `WebAssembly.compileStreaming` | blocked (MIME) | **works** |
725
+ | textures · `getImageData` | tainted canvas | **works** |
726
+ | `.glb` / `.gltf` (Three.js) | no MIME type → silently not drawn | **works** |
727
+
728
+ All seven were run in a real Chrome and confirmed **7/7**.
729
+
730
+ Apps with a router (React Router and friends) get the first page back when you reload on a
731
+ deep link. Never for requests with an extension (`app.js`) though — returning HTML for a
732
+ missing script dies with `Unexpected token '<'`, which hides the real cause (a typo in a filename).
733
+
734
+ ### It opens exactly as much as it says
735
+
736
+ Starting a server means opening your disk to somebody else.
737
+
738
+ - Bound to **`127.0.0.1` only**. `0.0.0.0` is not available at all — on an office network
739
+ that would let anyone read your source.
740
+ - Port **0** (the kernel hands out a free one). A fixed port steals someone else's.
741
+ - Paths cannot leave the working scope. `../` · `%2e%2e` · double encoding · absolute paths ·
742
+ null bytes · symlinks — eight of these are held shut by tests.
743
+ - **It only serves.** `POST` · `PUT` · `DELETE` are refused with 405.
744
+ - It shuts down when `deel` exits.
745
+
746
+ ---
747
+
748
+ ## Skills and plugins
749
+
750
+ **deel does not carry skills with it.** On startup it scans the machine it is running on and uses
751
+ whatever is there. On a clean PC: zero. On a PC with skills installed: those skills.
752
+
753
+ ```
754
+ project ./.deel/skills ./.claude/skills ./.deel/commands ./.claude/commands
755
+ user ~/.deel/skills ~/.claude/skills ~/.claude/commands
756
+ plugins ~/.claude/plugins/** ~/.deel/plugins/**
757
+ ```
758
+
759
+ Reads the Claude Code format: `SKILL.md` with YAML front matter, `commands/*.md`, `$ARGUMENTS`.
760
+
761
+ > **More** — Loaded in three stages · Fetching plugins · Deliberately not included
762
+ >
763
+ > **[Extending read →](docs/en/extend.md#skills-and-plugins)**
764
+
765
+ ---
766
+
767
+ ### The hidden latency of local models keeping the prefix cache alive
768
+
769
+ Ollama and llama.cpp reuse computation **only while the request starts the same way as the
770
+ last one.** Change one early character and everything after it — the entire conversation —
771
+ is recomputed. This is the usual hidden reason long local sessions feel slower and slower,
772
+ and it never shows up anywhere, because it is not an error.
773
+
774
+ deel routes every message to the right mode automatically, and that mode instruction used to
775
+ sit **early** in the prompt — every mode switch broke the whole cache. So the stable parts
776
+ (rules, folder, project fingerprint, user rules, memory, skills) are frozen at the front and
777
+ the per-turn parts (mode, pins) go last. A test pins this order down (`test/cache.test.js`).
778
+
779
+ Ollama also gets `keep_alive: 60m` — with the 5-minute default, the model unloads while you
780
+ glance at another window, and the first message after you come back recomputes everything.
781
+ Override with `DEEL_KEEP_ALIVE`. If you run llama.cpp directly, `--cache-reuse 256` on the
782
+ server side does the same job.
783
+
784
+ ## Reasoning effort
785
+
786
+ One answer means several model calls, and **each needs a different amount of thinking.**
787
+ All-high is slow; all-low wanders off.
788
+
789
+ The default is **one line**. What you want to know is how hard it is thinking right now,
790
+ not a stage table.
791
+
792
+ ```
793
+ $ /think
794
+
795
+ Effort medium (First call medium · Continue low · Stuck high)
796
+ harder /think high faster /think low
797
+ ```
798
+
799
+ | Profile | Character |
800
+ |---|---|
801
+ | `even` | Same effort everywhere predictable, slower |
802
+ | `save` (default) | Hard on the first decision only |
803
+ | `deep` | Everything one notch up — for hard work |
804
+
805
+ Set the profile with `/think profile save`. **Level and profile are different axes, so the
806
+ commands were split** — `/think high` and `/think save` used to set different things under
807
+ one name, which made the screen unreadable.
808
+
809
+ The stage table moved to `/think detail` (the default at developer level).
810
+
811
+ ```
812
+ $ /think detail
813
+
814
+ Effort medium (First call medium · Continue low · Stuck high)
815
+ Profile save Hard on the first call, shallow while continuing - usually the better trade
816
+
817
+ Stage Effort Out cap When
818
+ First call · medium 14,069 Deciding what to do
819
+ Continue ↓ low 12,310 Reading a tool result, picking the next move
820
+ Stuck ↑ high 15,827 The last tool returned an error
821
+
822
+ Caps are shared inside 16,384 (unknown, so a default) — /out
823
+ Context 40,960 · used 5,787
824
+ ```
825
+
826
+ That second-to-last line exists for a reason: **when all three caps are equal, it is the
827
+ only thing that says whether that is correct.** A low known cap makes them equal, and that
828
+ is fine. For a while all three read `16,384` always — which meant the table said nothing.
829
+
830
+ > **More** — Context length is read off the model · /out · Truncated tool calls
831
+ >
832
+ > **[Speed and spend read →](docs/en/tuning.md#reasoning-effort)**
833
+
834
+ ---
835
+
836
+ ## Auto-compaction
837
+
838
+ At 80% context, older turns are **summarised and folded** so work continues.
839
+ Plain truncation makes the model forget: it re-reads files and re-fixes what it already fixed.
840
+
841
+ ```
842
+ Folded 44 turns into a summary 10,399 3,170 tokens (70% smaller)
843
+ ```
844
+
845
+ The summary keeps goal / done / learned / decided / remaining. The cut point is chosen so a
846
+ **tool call is never separated from its result**splitting them makes the server return 400.
847
+ If the summary request fails, it falls back to plain trimming rather than stopping.
848
+
849
+ `/compact` folds on demand.
850
+
851
+ ---
852
+
853
+ ## Resuming a conversation
854
+
855
+ Close the terminal by accident, or reboot, and the conversation is still there.
856
+ Messages are written to `.deel/sessions/` **as each one completes**, so a crash
857
+ loses at most the message in flight.
858
+
859
+ ```
860
+ $ deel sessions
861
+
862
+ ── conversations in this folder ────────────────────────────────
863
+ 20260824-090200 just now 1 turn devstral-small-2507
864
+ fix the failing test
865
+ · 20260824-084500 2h ago 2 turns qwen2.5-coder:7b
866
+ switch src/a.js logging to the logger
867
+ ```
868
+
869
+ | Command | What it does |
870
+ |---|---|
871
+ | `deel --continue` | Resume the most recent conversation in this folder |
872
+ | `deel --resume <id>` | Resume a specific one |
873
+ | `deel sessions` | List what is stored |
874
+ | `deel sessions --rm <id>` | Delete one |
875
+
876
+ The format is `jsonl` — one message per line — so a power cut costs only the last line.
877
+ Resumed history keeps tool calls paired with their results, so work continues immediately.
878
+ Conversations older than 30 days and outside the most recent 30 are pruned automatically.
879
+
880
+ Everything lives in `.deel/sessions/` inside the working folder, and `.gitignore`
881
+ covers `.deel/` so it never reaches a repository.
882
+
883
+ ---
884
+
885
+ ## Starting over (`deel reset`)
886
+
887
+ Switching gateways, learned facts that went stale, handing the machine to someone else —
888
+ sometimes you want to go back to the beginning. Reinstalling does not do it: `~/.deel`
889
+ survives an install. Hence a command of its own.
890
+
891
+ ```
892
+ $ deel reset
893
+
894
+ ── what can be wiped ──────────────────────────────────────────
895
+ home C:\Users\me\.deel
896
+ working folder C:\work\myproject
897
+
898
+ connections 2
899
+ memory 8 lines
900
+ conversations 14
901
+ learned 2 places
902
+ evidence, exports, temp 6
903
+ plugins 3
904
+ sealed key DPAPI this PC, this account only
905
+
906
+ ── what is kept ───────────────────────────────────────────────
907
+ undo snapshots 41 needs all --hard
908
+ audit log 1,203 lines needs all --hard
909
+ written by you .deel/mcp.json · .deelignore
910
+ never touched, by any route.
911
+ ```
912
+
913
+ **Bare `deel reset` wipes nothing.** It shows what exists and asks.
914
+
915
+ | Command | What goes |
916
+ |---|---|
917
+ | `deel reset model` | connections and profiles, plus the key in the OS keystore |
918
+ | `deel reset memory` | memory (`.deel/memory.md`) |
919
+ | `deel reset sessions` | conversation history |
920
+ | `deel reset learned` | learned facts (this PC + this folder) |
921
+ | `deel reset plugins` | installed plugins |
922
+ | `deel reset all` | everything above **except plugins** |
923
+ | `deel reset all --hard` | plus undo snapshots and the audit log |
924
+ | `--yes` | skip the question (scripts, first-time provisioning) |
925
+
926
+ What it does **not** touch matters more.
927
+
928
+ | Kept | Why |
929
+ |---|---|
930
+ | `.deel/history/` (undo snapshots) | This is the safety net offered in place of an approval prompt. `--hard` only |
931
+ | `.deel/audit.jsonl` | The evidence for an internal review. `--hard` only |
932
+ | `.deel/mcp.json` · `.deelignore` · `DEEL.md` | You wrote these by hand. **Never touched, by any route** |
933
+ | Everything else in the working folder | Nothing outside `.deel` and the home folder is ever reached |
934
+
935
+ It runs on a broken config. That is usually *why* someone reaches for a reset, so
936
+ `deel reset` starts without reading the connection — the same reason `deel --version` answers
937
+ without one. Plugins take time to fetch again, so they stay out of `all`; ask for them by name.
938
+
939
+ ---
940
+
941
+ ## Attaching tools from outside (MCP)
942
+
943
+ A corporate wiki search, an issue tracker, a DB query tool — if a team publishes one as an MCP
944
+ server, deel uses it as a tool **without a code change**.
945
+
946
+ Configure in `.deel/mcp.json`. A Claude Code config can be copied over verbatim:
947
+
948
+ ```json
949
+ { "mcpServers": { "wiki": { "command": "node", "args": ["wiki-mcp.js"] } } }
950
+ ```
951
+
952
+ The model sees it as `mcp__wiki__search`. `/mcp` shows what is attached.
953
+
954
+ **Dependencies stay at zero.** The stdio transport is nothing but newline-delimited JSON-RPC
955
+ 2.0 over a child process's stdin/stdout, so `child_process` and `JSON` cover it. No SDK.
956
+
957
+ > **More** — But this is somebody else's program
958
+ >
959
+ > **[Extending read →](docs/en/extend.md#attaching-tools-from-outside-mcp)**
960
+
961
+ ---
962
+
963
+ ## Inside your editor (ACP)
964
+
965
+ A tool that makes you open one more terminal window stops being used after about two weeks.
966
+ Developers live inside the IDE. So deel speaks **ACP** (Agent Client Protocol) — Zed,
967
+ JetBrains, Neovim and Emacs attach to it **without changing a line on their side**.
968
+
969
+ One command in your editor's settings:
970
+
971
+ ```
972
+ deel acp
973
+ ```
974
+
975
+ The editor spawns that as a child process and exchanges newline-delimited JSON-RPC 2.0 over
976
+ stdio. It is not a command you type yourself.
977
+
978
+ **What you get once it is attached:**
979
+
980
+ | In the editor | From deel |
981
+ |---|---|
982
+ | Streaming reply pane | The model's text and its reasoning |
983
+ | Tool list with icons and status | `Read` is a read, `Edit` is an edit, `Bash` is an execution — **the kind is sent**, not just a name |
984
+ | Clickable file links | The **absolute path** of every file touched |
985
+ | Approval dialog | deel's safety rails, rendered as the editor's own prompt (`allow once` · `always allow` · `reject`) |
986
+ | Mode picker | deel's seven work modes (auto · code · plan · architect · debug · ask · orchestrator) |
987
+ | Stop button | Reaches the turn mid-flight, even while waiting on the model |
988
+ | Past conversations | Still there after a restart. They live in the **same place** as the terminal's, so a session started in the editor can be picked up with `deel --resume` |
989
+
990
+ **Still zero dependencies.** Same reason as MCP — newline-delimited JSON-RPC 2.0 is the whole
991
+ transport, so no SDK is needed.
992
+
993
+ > **More** — Details — the places this breaks silently
994
+ >
995
+ > **[Extending read →](docs/en/extend.md#inside-your-editor-acp)**
996
+
997
+ ---
998
+
999
+ ## Keeping secrets out of the conversation
1000
+
1001
+ People rarely paste a key. The leak is almost always **command output**.
1002
+
1003
+ ```
1004
+ env OPENAI_API_KEY=sk-proj-…
1005
+ git remote -v https://user:token@github.com/…
1006
+ curl -v > Authorization: Bearer eyJ…
1007
+ a failing test log the whole connection string
1008
+ ```
1009
+
1010
+ That text goes to the model **and** gets written to `.deel/sessions/*.jsonl` on disk. That
1011
+ file is later re-read by `/recall` and can end up inside a `deel pack` bundle. Leak once and
1012
+ you have several copies.
1013
+
1014
+ So it is masked at the single point where tool output enters the conversation.
1015
+
1016
+ ```
1017
+ Bash(env | grep API) done
1018
+ 2 secret-looking values entered the conversation (openai · env var) — masked before the model
1019
+ ```
1020
+
1021
+ What it looks for: private-key blocks · OpenAI/Anthropic keys · GitHub tokens · Slack tokens ·
1022
+ AWS keys · Google keys · JWTs · credentials embedded in URLs · `Authorization`-family headers ·
1023
+ env vars named `…KEY` / `…TOKEN` / `…SECRET` / `…PASSWORD`. Plus **the configured gateway key
1024
+ regardless of its shape** — that one is not a guess, it is a known value.
1025
+
1026
+ ### File contents are deliberately not masked
1027
+
1028
+ `.env` is exactly where masking feels most tempting, and exactly where it backfires: the model
1029
+ sees the masked text, edits it, writes it back and `«가림»` lands where the real key was.
1030
+ **Protecting the secret would destroy it.**
1031
+
1032
+ So on the file side it reports instead of rewriting.
1033
+
1034
+ ```
1035
+ Read(.env) 12 lines
1036
+ ! 3 secret-looking values entered the conversation (env var)
1037
+ file contents are not masked (masking them would erase the key on write-back)
1038
+ ```
1039
+
1040
+ Saying plainly what cannot be stopped beats claiming it was stopped while corrupting the file.
1041
+ Either way it lands in the audit log.
1042
+
1043
+ ---
1044
+
1045
+ ## Safety
1046
+
1047
+ Instead of approval prompts, the design makes things **reversible**. The default `auto` mode
1048
+ does not ask.
1049
+
1050
+ | Mechanism | Detail |
1051
+ |---|---|
1052
+ | **Undo** | Snapshot before every write. `/undo` restores per turn. **Includes moves and deletes done through `Bash`** |
1053
+ | **Change display** | The changed lines are shown on every edit; `/diff` for the whole session |
1054
+ | **Scope** | Outside the starting folder is refused, even if the model insists |
1055
+ | **Blocked commands** | Only irreversible ones (disk format, recursive delete, `--force` push) |
1056
+ | **No re-run** | A mutating command is never retried after failure |
1057
+ | **Interrupt** | Ctrl+C stops mid-answer and leaves the conversation valid |
1058
+ | **Spin guard** | Three identical failures stop the turn, with the reason |
1059
+ | **Not read** | Other tools' private stores, and deel's own logs and config (the key), are refused |
1060
+ | **Audit log** | Everything recorded in `.deel/audit.jsonl` |
1061
+
1062
+ | Mode | Asks when |
1063
+ |---|---|
1064
+ | `auto` (default) | Never undo is the safety net |
1065
+ | `confirm` | Irreversible commands only |
1066
+ | `strict` | All file changes and commands |
1067
+
1068
+ Undo history stores whole file contents, so repeated edits to large files add up. Past 32MB
1069
+ it keeps the **most recent 50 turns** and drops the rest. What you just did is always
1070
+ undoable; `/status` shows how large the history currently is.
1071
+
1072
+ > **More** Files removed through Bash come back too · What it will not read
1073
+ >
1074
+ > **[Safety and corporate review read →](docs/en/safety.md#safety)**
1075
+
1076
+ ---
1077
+
1078
+ ## Corporate review package
1079
+
1080
+ ```bash
1081
+ deel pack --out deel-import.zip
1082
+ ```
1083
+
1084
+ ```
1085
+ deel-import.zip
1086
+ 94 files · 509.6KB
1087
+
1088
+ Dependencies 0
1089
+ Install scripts none
1090
+ External imports 0
1091
+ Network calls 3 sites (configured address only)
1092
+ Ports opened 1 site (/preview only)
1093
+ ```
1094
+
1095
+ The zip carries **one document for people and two for machines.** A corporate review is
1096
+ not a human-only process security feeds an SBOM to a scanner, and operations reads the
1097
+ audit-log spec to write SIEM ingestion rules.
1098
+
1099
+ | File | What |
1100
+ |---|---|
1101
+ | `import-review.txt` | Dependencies · install scripts · **every network and process-spawn call site found by scanning the source** (file:line) · the three outbound lanes · SHA-256 per file |
1102
+ | `sbom.cdx.json` | **SBOM (CycloneDX 1.5).** Feed it straight to a scanner. One component per file with SHA-256; dependencies stated as an **explicit empty array** — "not declared" and "none" are different claims |
1103
+ | `audit-spec.json` | Egress list (per lane: when, where, what, how it's stopped, and the source location) · **audit-log spec** (field names and meanings, plus what is never recorded) · file hashes |
1104
+
1105
+ ```bash
1106
+ deel audit # the human-readable sheet only
1107
+ deel sbom # the two machine-readable ones, on stdout (deel sbom | jq)
1108
+ deel sbom --out review.json # to a file
1109
+ deel sbom --only sbom # just the SBOM
1110
+ ```
1111
+
1112
+ With the screen language set to English these three, and the `deel pack` archive itself,
1113
+ come out in English — file names included (`deel pack` writes `deel-import.zip`).
1114
+
1115
+ All three are generated by scanning the source, never written by hand — hand-written sheets
1116
+ drift, and **a review document that drifts is worse than none.** Find one wrong line and the
1117
+ reviewer stops trusting the rest. The audit-log spec is the one hand-written part, so a test
1118
+ checks it against real log records on every run.
1119
+
1120
+ > **More** — Diagnosing a corporate gateway
1121
+ >
1122
+ > **[Safety and corporate review read →](docs/en/safety.md#corporate-review-package)**
1123
+
1124
+ ---
1125
+
1126
+ ## Configuration
1127
+
1128
+ Stored in `~/.deel/config.json`. A `.deel/config.json` in the project folder takes precedence.
1129
+
1130
+ > **More** — Supported servers · Environment variables · Flags · Project rules
1131
+ >
1132
+ > **[Configuration read →](docs/en/config.md#configuration)**
1133
+
1134
+ ---
1135
+
1136
+ ## Troubleshooting
1137
+
1138
+ | Symptom | Check |
1139
+ |---|---|
1140
+ | `address not found` | Typo, DNS, VPN / intranet connectivity |
1141
+ | `connection refused` | Server is down or the port differs |
1142
+ | certificate error | `set NODE_EXTRA_CA_CERTS=C:\path\corp-ca.pem` |
1143
+ | behind a proxy | `set HTTPS_PROXY=http://proxy:port` (with auth: `http://user:pw@proxy:port`). If the first screen and `/status` show `proxy …`, it is in use. Exclude hosts with `NO_PROXY=.corp.com,10.1.2.3`; turn it off entirely with `"proxy": "none"` in the config |
1144
+ | the proxy answers 407 | Put `user:pw@` into the proxy address. Proxies that only accept NTLM · Negotiate are not supported — ask the admin for Basic or an unauthenticated address |
1145
+ | 401 / 403 | Wrong key or auth header style (four are tried automatically) |
1146
+ | `address not permitted` | The lock did its job — pick a connection with `/model` |
1147
+ | Tool calls don't work | Run `deel diagnose`. Small models (1B–3B) often can't |
1148
+ | Empty replies | The server ignores streaming. deel retries once, then turns streaming off for the session |
1149
+ | Large files cut off mid-write | Check `/out` and raise it — the cap may be sitting at the 16,384 default because it could not be discovered |
1150
+ | Only `HTTP 400` shows | The server's own message is shown verbatim. If it is a length problem the number is read and applied automatically |
1151
+ | `429` · `503` shows | The gateway pushed back for a moment. deel waits and calls again, up to three times (honouring `Retry-After`). If it keeps happening, check your quota |
1152
+ | `deel scan` finds nothing | Server is off or on another port — use `--ports` |
1153
+
1154
+ ---
1155
+
1156
+ ## Development
1157
+
1158
+ ```bash
1159
+ npm test Full suite (~5,890 checks; a few are TTY-dependent)
1160
+ npm run coverage Which lines the tests actually execute
1161
+ npm run verify Import + network checks only
1162
+ npm run bench Edit success rate
1163
+ npm run demo See what the UI actually looks like
1164
+ npm run check Syntax check every file
1165
+ ```
1166
+
1167
+ Tests run against a **fake gateway**, so the loop, streaming, tool execution, undo and compaction
1168
+ are verified deterministically without any model. ZIP output is cross-checked with the real
1169
+ `unzip`; the TAR reader is fed archives produced by the real `tar`.
1170
+
1171
+ `npm test` runs each file separately and reports **per-file exit codes**, because the exit code
1172
+ — not the pass marks on screen — is what CI reads, and the two can disagree: a file can pass
1173
+ every check and still die on the way out, leaving the screen green and the exit code 1. That
1174
+ happened once on Windows and cost a lot of time. The runner does not stop at the first failure,
1175
+ so one run tells you everything.
1176
+
1177
+ | Suite | Checks | Covers |
1178
+ |---|---|---|
1179
+ | `smoke` | 20 | Tools, scope, undo, audit log |
1180
+ | `loop` | 16 | Agent loop, streaming, tool calls |
1181
+ | `guard` | 24 | **What it refuses to do** — denied edits, unknown tools, repeated mutations, out-of-scope writes |
1182
+ | `network` | 30 | Nothing escapes the configured address |
1183
+ | `web` | 25 | Web reads stay read-only |
1184
+ | `abort` · `steer` | 16 · 15 | Ctrl+C leaves the conversation valid · a line typed mid-turn rides the next call |
1185
+ | `parallel` | 23 | Read-only tools run together; checklists |
1186
+ | `cli` | 75 | **Spawns the real `deel`** and drives it to completion |
1187
+ | `setup` | 42 | First-run wizard, driven through a fake TTY |
1188
+ | `detect` | 66 | Identifying shape and auth from one address |
1189
+ | `modes` · `route` | 89 · 33 | Work modes; auto-switching from Auto |
1190
+ | `ctxsize` | 43 | Reading context length off the model |
1191
+ | `commands` · `commands-more` | 128 · 62 | Every slash command |
1192
+ | `ui` · `ui2` | 60 · 40 | Password masking, CJK width, status line, session list, Excel→text |
1193
+ | `encoding` · `xlsx` | 68 · 72 | Legacy-encoding detection; Excel reading |
1194
+ | `compact` | 21 | Summary folding, pairing intact, graceful fallback |
1195
+ | `store` | 34 | Session persistence, resume, crash recovery |
1196
+ | `scan` | 29 | Distinguishing multiple runtimes |
1197
+ | `plugins` | 38 | Plugin fetch/pack, ZIP/TAR |
1198
+ | `no-bundle` | 12 | Nothing foreign in the published package; test-file hygiene |
1199
+ | `edit-bench` | 20 cases | Edit success rate |
1200
+
1201
+ > **More** — Coverage · Layout
1202
+ >
1203
+ > **[Development read →](docs/en/develop.md#development)**
1204
+
1205
+ ---
1206
+
1207
+ ## Release notes
1208
+
1209
+ | Version | What changed |
1210
+ |---|---|
1211
+ | **[1.10.0](docs/en/releases/1.10.md#1100)** | ESC actually stops · a full context carries on inside the same turn · every vendor endpoint measured |
1212
+ | [1.9.2](docs/en/releases/1.9.md#192) | Guards that said they were blocking were not blocking · folding lost the request and the outstanding work |
1213
+ | [1.9.1](docs/en/releases/1.9.md#191) | MCP tools with Korean names all looked the same to the model — names are now distinct and stable |
1214
+ | **[1.9.0](docs/en/releases/1.9.md#190)** | Tables are drawn as tables · reasoning effort reaches Claude and Bedrock · tool schemas shaped per vendor · only the changed part of a file is re-sent |
1215
+ | **[1.8.0](docs/en/releases/1.8.md#180)** | A full day against a gateway that hands out one-hour tokens — fetch the key instead of storing it · `deel reset` · an English screen that is actually English |
1216
+
1217
+ The five most recent are listed here. Every version, and why each thing changed, is in the **[release notes](docs/en/releases.md)**.
1218
+
1219
+ ---
1220
+
1221
+ ## Licence
1222
+
1223
+ [MIT](LICENSE)