oxios 1.12.0

Oxios Agent OS — Agent Operating System powered by oxi-sdk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
# RFC-026: 크레이트 구조 재설계 — 애플리케이션 크레이트를 바이너리로 통합

> **Status:** Proposed
> **Created:** 2026-06-21
> **Supersedes:** AGENTS.md §Release (crates.io 배포 대상 변경)

## Problem

현재 oxios 워크스페이스는 12개 크레이트로 구성되어 있다. 이 중 7개는 재사용 가능한
코어 라이브러리이고, 5개(oxios-web, oxios-cli, oxios-telegram, oxios-bench, oxios
바이너리)는 애플리케이션 고유 코드다. 문제는 후자가 **재사용 불가능한 코드를 재사용
가능한 라이브러리처럼 패키징**하고 있다는 점이다.

### 구체적 증상

1. **oxios-web, oxios-cli, oxios-telegram은 어떤 크레이트도 import하지 않는다.**
   오직 `oxios` 바이너리만 사용한다. crates.io에 배포할 독립적 가치가 없다.

2. **oxi-sdk 버전 충돌.** 게시된 `oxios-kernel 1.5.1``oxi-sdk 0.35.0`에,
   워크스페이스는 `oxi-sdk 0.37.1`에 묶여 있다. oxios-web을 배포하려 하면 두 버전의
   `oxi-ai`가 동시에 참조되어 컴파일 에러가 발생한다. (2026-06-21 발생)

3. **`surface/` vs `channels/` 인위적 구분.** Web은 `surface/`에, CLI/Telegram은
   `channels/`에 있다. 둘 다 "사용자 인터페이스"인데 폴더가 나뉘어 있다.

4. **바이너리가 비정상적으로 얇음.** `src/`는 5.6K LOC. 실제 애플리케이션 코드의
   대부분이 별도 크레이트에 분산되어 있다.

5. **React 프론트엔드(43K LOC TS)가 Rust 크레이트 내부에 위치.** oxios-web 크레이트의
   `web/` 디렉토리에 TypeScript 프로젝트 전체가 들어있다.

### 근본 원인

> **애플리케이션 고유 코드를 재사용 가능한 라이브러리로 오분류했다.**

Feature-gating은 별도 크레이트 없이도 module 수준에서 달성할 수 있다. `surface/`와
`channels/`의 분리는 아키텍처적 필요가 아니라 historical artifact다.

## Design Overview

### 핵심 원칙

> **`crates/` = 재사용 가능한 라이브러리. `src/` = oxios 바이너리(서버).**
> TS 프론트엔드는 루트 `web/`에 독립 프로젝트로 존재한다.

### 범위

이 RFC는 **크레이트 구조 재편**만을 다룬다. rust-embed 제거(에셋 서빙 방식 변경)는
런타임 동작에 영향을 미치는 별개 관심사이므로 **별도 RFC로 분리**한다. 이 설계에서는
rust-embed를 현행 유지한다.

### 제안 구조

```
oxios/
├── crates/                       재사용 가능한 라이브러리 (crates.io 배포)
│   ├── oxios-kernel/             48K LOC  — 에이전트 커널
│   ├── oxios-memory/             13K LOC  — 계층형 메모리
│   ├── oxios-markdown/           8K LOC   — 지식베이스
│   ├── oxios-ouroboros/          2K LOC   — 스펙 프로토콜
│   ├── oxios-calendar/           2K LOC   — 캘린더
│   ├── oxios-gateway/            2K LOC   — 메시지 라우팅
│   └── oxios-mcp/                1K LOC   — MCP 클라이언트
│
├── src/                          oxios 바이너리 (서버)
│   ├── main.rs                   진입점, CLI 파싱, 모듈 선언
│   ├── kernel.rs                 커널 어셈블러
│   ├── surface.rs                서피스 활성화 (기존 유지)
│   ├── web_dist.rs               프론트엔드 다운로드 (기존 유지)
│   ├── commands/                 CLI 서브커맨드 (기존 유지)
│   ├── otel.rs                   OpenTelemetry (기존 유지)
│   │
│   ├── api/                      ← was surface/oxios-web/src/ (HTTP API 서버)
│   │   ├── mod.rs                ← lib.rs 변환 (모듈 선언 + re-exports)
│   │   ├── server.rs             AppState
│   │   ├── plugin.rs             WebSurface 구현 + 정적 파일 서빙
│   │   ├── middleware.rs         Rate limiter
│   │   ├── bridge.rs             WebBridge (메시지 브릿지)
│   │   ├── error.rs              AppError
│   │   ├── format.rs             포매터
│   │   ├── api_docs.rs           OpenAPI/Swagger
│   │   ├── persona_routes.rs     페르소나 API
│   │   └── routes/               REST API 라우트 (20개 모듈)
│   │       ├── mod.rs
│   │       ├── chat.rs
│   │       ├── engine_routes.rs
│   │       ├── knowledge_routes.rs
│   │       ├── events.rs
│   │       └── ... (기존 파일 그대로)
│   │
│   └── channels/                 ← was channels/oxios-{cli,telegram}/
│       ├── mod.rs
│       ├── cli/                  ← was oxios-cli/src/ (7 files, 923 LOC)
│       │   ├── mod.rs
│       │   ├── channel.rs
│       │   ├── commands.rs
│       │   ├── format.rs
│       │   ├── interactive.rs
│       │   ├── plugin.rs
│       │   └── session.rs
│       └── telegram/             ← was oxios-telegram/src/ (3 files, 846 LOC)
│           ├── mod.rs
│           ├── format.rs
│           └── plugin.rs
│
├── web/                          ← was surface/oxios-web/web/ (React 프로젝트)
│   ├── package.json
│   ├── bun.lock
│   ├── vite.config.ts
│   ├── biome.json
│   ├── index.html
│   ├── public/
│   ├── src/                      43K LOC TypeScript
│   ├── e2e/
│   └── dist/                     빌드 산출물 (gitignored, CI가 생성)
│
├── share/                        기본 리소스 (config, skills)
├── benchmarks/                   벤치마크 (oxios-bench, 독립 크레이트)
├── docs/
└── tests/
```

### 사라지는 것

| 대상 | 운명 |
|------|------|
| `surface/` 디렉토리 | 삭제. `src/api/`로 흡수 |
| `channels/` 디렉토리 | 삭제. `src/channels/`로 흡수 |
| `oxios-web` 크레이트 | `src/api/` module로 흡수 |
| `oxios-cli` 크레이트 | `src/channels/cli/` module로 흡수 |
| `oxios-telegram` 크레이트 | `src/channels/telegram/` module로 흡수 |

### 유지되는 것

| 대상 | 이유 |
|------|------|
| 7개 코어 라이브러리 크레이트 | 재사용 가능, crates.io 배포 가치 있음 |
| `oxios-bench` | 독립 도구, oxios 의존성 없음 |
| Feature-gating | `#[cfg(feature = "web")]` module로 동일 동작 |
| rust-embed | 현행 유지. 에셋 서빙 방식은 별도 RFC |
| `Surface` / `Channel` trait | `oxios-gateway`에 정의, 그대로 사용 |
| `otel`, `embedding-gguf`, `browser` feature | 재편에 영향 없음 |

## Detailed Design

### 1. Cargo.toml 변경

#### Workspace members 축소

```toml
# Before (11 members)
[workspace]
members = [
    "crates/oxios-mcp",
    "crates/oxios-memory",
    "crates/oxios-calendar",
    "crates/oxios-kernel",
    "crates/oxios-markdown",
    "crates/oxios-ouroboros",
    "crates/oxios-gateway",
    "surface/oxios-web",
    "channels/oxios-cli",
    "channels/oxios-telegram",
    "benchmarks/oxios-bench",
]

# After (8 members)
[workspace]
members = [
    "crates/oxios-mcp",
    "crates/oxios-memory",
    "crates/oxios-calendar",
    "crates/oxios-kernel",
    "crates/oxios-markdown",
    "crates/oxios-ouroboros",
    "crates/oxios-gateway",
    "benchmarks/oxios-bench",
]
```

#### Features 재구성

optional crate dependency(`dep:oxios-web`) 대신 optional regular dependency로 전환.

```toml
# Before
[features]
default = ["web", "cli", "browser", "sqlite-memory"]
web = ["dep:oxios-web"]
cli = ["dep:oxios-cli"]
telegram = ["dep:oxios-telegram"]
browser = []
sqlite-memory = ["oxios-kernel/sqlite-memory"]
embedding-gguf = ["oxios-kernel/embedding-gguf"]
otel = ["oxios-kernel/otel", "dep:opentelemetry", "dep:opentelemetry_sdk"]

# After — 동일한 feature 이름, module 수준 cfg gate
[features]
default = ["web", "cli", "browser", "sqlite-memory"]
web = ["dep:axum", "dep:tower", "dep:tower-http", "dep:rust-embed",
       "dep:mime_guess", "dep:futures-util", "dep:tokio-stream",
       "dep:utoipa", "dep:utoipa-swagger-ui"]
cli = ["dep:reedline"]
telegram = []
browser = []
sqlite-memory = ["oxios-kernel/sqlite-memory"]
embedding-gguf = ["oxios-kernel/embedding-gguf"]
otel = ["oxios-kernel/otel", "dep:opentelemetry", "dep:opentelemetry_sdk"]
```

#### Dependencies 이관

oxios-web, oxios-cli의 의존성을 바이너리 `[dependencies]`로 이관. oxios-telegram은
의존성이 이미 바이너리에 존재 (`reqwest`, `tokio`, `serde` 등 workspace 공통).

```toml
[dependencies]
# ── web feature (was oxios-web deps) ──────────────────────────────
axum = { version = "0.8", features = ["ws"], optional = true }
tower = { version = "0.5", optional = true }
tower-http = { version = "0.6", features = ["cors"], optional = true }
rust-embed = { version = "8", features = ["mime-guess"], optional = true }
mime_guess = { version = "2", optional = true }
futures-util = { version = "0.3", optional = true }
tokio-stream = { version = "0.1", features = ["sync"], optional = true }
utoipa = { version = "5", features = ["axum_extras", "uuid", "chrono"], optional = true }
utoipa-swagger-ui = { version = "9", features = ["axum"], optional = true }

# ── cli feature (was oxios-cli deps) ──────────────────────────────
reedline = { version = "0.38", optional = true }

# ── telegram feature (was oxios-telegram deps) ────────────────────
# reqwest, tokio, serde, serde_json, async-trait, chrono, uuid, tracing
# → 이미 바이너리 [dependencies]에 존재. 추가 이관 불필요.

# ── 기존 의존성 (변경 없음) ───────────────────────────────────────
oxios-kernel = { version = "1.5.1", path = "crates/oxios-kernel", default-features = false }
oxios-calendar = { version = "1.5.1", path = "crates/oxios-calendar" }
oxios-markdown = { version = "1.5.1", path = "crates/oxios-markdown" }
oxios-ouroboros = { version = "1.5.1", path = "crates/oxios-ouroboros" }
oxios-gateway = { version = "1.5.1", path = "crates/oxios-gateway" }
oxi-sdk = { workspace = true }
# ... (나머지 기존 의존성 그대로)
```

#### `[patch.crates-io]` 변경 없음

현재 활성 패치는 `oxios-kernel = { path = "crates/oxios-kernel" }` 하나뿐이며,
oxios-web/cli/telegram 패치는 존재하지 않았다. 따라서 제거할 것이 없다.

#### `[dev-dependencies]` 병합

oxios-web의 `tempfile` dev-dep이 바이너리 dev-dep에 이미 존재하므로 추가 이관 불필요.

#### oxios-web/web 경로 이동에 따른 rust-embed 폴더 경로

```rust
// Before: surface/oxios-web/ 기준 → web/dist/
#[derive(Embed)]
#[folder = "web/dist/"]
struct EmbeddedAssets;

// After: 워크스페이스 루트 기준 → web/dist/ (경로 동일)
// rust-embed의 #[folder]는 Cargo.toml 위치 기준이므로
// web/ 이 루트로 이동하면 "web/dist/" 경로가 그대로 유효
```

### 2. Module 구조

#### `src/main.rs` — 모듈 선언 추가

```rust
// 기존 선언
mod commands;
mod kernel;
mod otel;
mod surface;
mod web_dist;

// 추가
#[cfg(feature = "web")]
mod api;

mod channels;  // 내부에서 #[cfg(feature = "cli/telegram")]으로 gate
```

#### `src/api/mod.rs` — lib.rs 변환

oxios-web의 `lib.rs`를 module 선언으로 변환. **부모에서 `#[cfg(feature = "web")]`로
gate하므로 내부 모듈은 개별 gate 불필요.**

```rust
//! Web dashboard HTTP API server.

pub mod api_docs;
pub mod bridge;
pub mod error;
pub mod format;
pub mod middleware;
pub mod persona_routes;
pub mod plugin;
pub mod routes;
pub mod server;

pub use bridge::{WebBridge, WebBridgeHandle};
pub use plugin::WebSurface;
pub use server::AppState;
```

#### `src/surface.rs` — import 경로 변경

```rust
// Before
#[cfg(feature = "web")]
let surfaces: Vec<Box<dyn Surface>> = vec![Box::new(oxios_web::WebSurface::new())];

// After
#[cfg(feature = "web")]
let surfaces: Vec<Box<dyn Surface>> = vec![Box::new(crate::api::WebSurface::new())];
```

#### `src/channels/mod.rs`

```rust
//! In-process communication channels.

#[cfg(feature = "cli")]
pub mod cli;

#[cfg(feature = "telegram")]
pub mod telegram;
```

#### `src/main.rs` — 채널 인스턴스화 경로 변경

```rust
// Before (line 25-28)
#[cfg(feature = "cli")]
use oxios_cli::CliPlugin;
#[cfg(feature = "telegram")]
use oxios_telegram::TelegramPlugin;

// After
#[cfg(feature = "cli")]
use crate::channels::cli::CliPlugin;
#[cfg(feature = "telegram")]
use crate::channels::telegram::TelegramPlugin;
```

```rust
// Before (line 1989-1994) — CLI interactive mode
let cli_channel = oxios_cli::CliChannel::new(256);
let handle = cli_channel.handle();
let mut loop_ = oxios_cli::InteractiveLoop::new(handle);

// After
let cli_channel = crate::channels::cli::CliChannel::new(256);
let handle = cli_channel.handle();
let mut loop_ = crate::channels::cli::InteractiveLoop::new(handle);
```

`build_channel_plugins()` (line 2903-2911)는 `CliPlugin::new()` / `TelegramPlugin::new()`
참조만 있고 이는 위 use 선언 변경으로 자동 해결됨.

### 3. `static/` 디렉토리 처리

`surface/oxios-web/static/`은 **Rust 코드에서 참조되지 않는다** (코드 검증 완료).
rust-embed 대상도 아니다 (`#[folder = "web/dist/"]`만 임베드).

내용 분석:

| 파일 | 실체 | 처리 |
|------|------|------|
| `Containerfile` | Docker/Container 빌드 정의 | 프로젝트 루트로 이동 |
| `default-config.toml` | `share/default-config.toml`과 동일 | 삭제 (중복) |
| `default-skills/` | `share/default-skills/`과 동일 | 삭제 (중복) |
| `default-programs/` | 과거 program.toml 형식 (RFC-009 이전) | 삭제 (사용 안 함) |
| `knowledge/` | files.md 정적 앱. `/knowledge/` 경로로 서빙됨 (middleware.rs:111) | `share/knowledge/`로 이동 |

`Containerfile`은 `COPY . .` 후 `cargo build --release -p oxios`를 수행하므로, `static/`
위치와 무관하게 작동한다.

### 4. crates.io 배포 변경

#### Before (수동 + CI 혼합, 불완전)

```
① oxios-markdown, oxios-mcp, oxios-ouroboros, oxios-memory     (CI publish.yml)
② oxios-calendar → oxios-markdown                               (CI publish.yml)
③ oxios-kernel → {ouroboros, markdown, calendar, mcp, memory}   (CI publish.yml)
④ oxios-gateway → oxios-kernel                                  (CI publish.yml)
⑤ oxios-web, oxios-cli, oxios-telegram, oxios, oxios-bench     (수동, 1.2.0에서 정체)
```

#### After (CI 전 자동, 9개)

```
① oxios-markdown, oxios-mcp, oxios-ouroboros, oxios-memory
② oxios-calendar → oxios-markdown
③ oxios-kernel → {ouroboros, markdown, calendar, mcp, memory}
④ oxios-gateway → oxios-kernel
⑤ oxios (binary) → {kernel, gateway, markdown, ouroboros, calendar}
⑥ oxios-bench (독립, oxios 의존성 없음)
```

- oxios-web/cli/telegram은 별도 크레이트가 아니므로 배포 불필요
- 동기화 대상 감소: 12 → 9. 버전 충돌 위험 **감소** (완전 제거 아님 — 커널의
  oxi-sdk 의존성은 별도 크레이트이므로 잔여 위험 존재)
- 바이너리(`oxios`)는 코어 크레이트가 모두 crates.io에 보인 후 배포

#### 바이너리 배포 시 `web/dist/` 제외

rust-embed가 `web/dist/`를 참조하므로, 바이너리 패키지에서 `web/` 디렉토리 자체를
제외해야 한다. 이미 `web/dist/`는 `.gitignore`에 있으므로, `cargo publish`는
git-tracked 파일만 포함한다. 단 `web/node_modules/` 등도 `.gitignore`에 있는지 확인.

### 5. CI/CD 변경

#### release.yml — web dist 빌드 경로

```yaml
# Before
- name: Build web assets
  working-directory: surface/oxios-web/web
  run: bun install && bun run build

- name: Package web assets
  run: |
    cd surface/oxios-web/web/dist
    zip -r $GITHUB_WORKSPACE/web-dist.zip .

# After
- name: Build web assets
  working-directory: web
  run: bun install && bun run build

- name: Package web assets
  run: |
    cd web/dist
    zip -r $GITHUB_WORKSPACE/web-dist.zip .
```

#### publish.yml — 배포 대상 확장

```yaml
# matrix에 oxios, oxios-bench 추가
matrix:
  crate:
    - oxios-markdown
    - oxios-mcp
    - oxios-ouroboros
    - oxios-memory
    - oxios-calendar
    - oxios-kernel
    - oxios-gateway
    - oxios        # ← 추가 (binary)
    - oxios-bench  # ← 추가 (독립)
```

바이너리는 워크스페이스 루트에 있으므로 `working-directory: crates/${{ matrix.crate }}`가
작동하지 않는다. `publish` step에서 경로 분기 필요:

```yaml
- name: Publish ${{ matrix.crate }}
  working-directory: ${{ matrix.crate == 'oxios' && '.' || format('crates/{0}', matrix.crate) }}
  env:
    CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN || secrets.CARGO_REGISTRY_TOKEN }}
  run: |
    # ... (기존 publish 로직)
```

`WAIT` 매핑에 추가:

```
oxios)        WAIT="oxios-gateway" ;;
oxios-bench)  WAIT="" ;;  # 독립, 대기 불필요
```

#### package-check — 검증 대상 확장

```yaml
for crate in oxios-markdown oxios-mcp oxios-ouroboros oxios-memory \
             oxios-calendar oxios-kernel oxios-gateway \
             oxios oxios-bench; do
```

바이너리는 `cargo package -p oxios`로 패키징 검증.

## Migration Plan

> **중요:** Phase 2(Cargo.toml)와 Phase 3(import 경로)는 상호 의존한다.
> Phase 2 후 Phase 3 전에는 컴파일이 불가능하다. 두 Phase를 **한 단위로** 진행하고
> 완료 후 `cargo check`로 검증해야 한다.

### Phase 1: 파일 이동 (구조 변경만, 코드 수정 없음)

1. `surface/oxios-web/src/``src/api/` (git mv)
2. `surface/oxios-web/web/``web/` (git mv)
3. `channels/oxios-cli/src/``src/channels/cli/` (git mv)
4. `channels/oxios-telegram/src/``src/channels/telegram/` (git mv)
5. `surface/oxios-web/static/Containerfile` → 프로젝트 루트 (git mv)
6. `surface/oxios-web/static/knowledge/``share/knowledge/` (git mv)
7. `surface/oxios-web/static/` 나머지 (중복) 삭제
8. `surface/oxios-web/Cargo.toml`, `channels/oxios-cli/Cargo.toml`,
   `channels/oxios-telegram/Cargo.toml` 삭제
9. `surface/`, `channels/` 빈 디렉토리 삭제

### Phase 2-3: Cargo.toml 재구성 + Import 경로 수정 (동시 진행)

1. **Workspace members**에서 3개 크레이트 제거
2. **`[features]`** 재구성 (optional dep → optional regular dep)
3. **`[dependencies]`**에 web/cli 의존성 이관 (optional = true)
4. **`src/main.rs`**: `mod api;`, `mod channels;` 선언 추가
5. **`src/api/mod.rs`**: `lib.rs`를 module 선언으로 변환, `#![warn(missing_docs)]` 제거
   (바이너리는 공개 라이브러리가 아니므로)
6. **`src/surface.rs`**: `oxios_web::``crate::api::`
7. **`src/main.rs`**: `oxios_cli::` / `oxios_telegram::``crate::channels::cli::` /
   `crate::channels::telegram::`
8. **`src/api/`** 내부: `crate::xxx` (oxios-web 기준) → `crate::api::xxx` 참조 확인
9. `cargo check --workspace --all-features` 로 전수 검사

### Phase 4: 정리

1. `src/channels/cli/mod.rs`, `src/channels/telegram/mod.rs`: 각 crate의 `lib.rs`   module 선언으로 변환, `#![warn(missing_docs)]` 제거
2. `pub` 가시성 조정: 외부 크레이트가 없으므로 `pub(crate)` 권장
3. 통합 테스트 (`tests/`)에서 `oxios_web` / `oxios_cli` / `oxios_telegram` crate 이름
   참조 확인 및 수정
4. `.gitignore``web/node_modules/`, `web/dist/` 포함 확인

### Phase 5: CI/CD 업데이트

1. `release.yml`: web dist 빌드 경로 변경 (`surface/oxios-web/web``web`)
2. `publish.yml`: matrix에 `oxios`, `oxios-bench` 추가, `working-directory` 분기
3. `ci.yml`: workspace 구조 변경 반영 (member 감소)

### Phase 6: 검증

```bash
# Feature 조합별 빌드
cargo build                                    # default (web, cli, browser, sqlite-memory)
cargo build --no-default-features --features cli          # web 없이
cargo build --no-default-features --features web          # cli 없이
cargo build --features telegram                           # telegram 추가
cargo build --all-features                                # 전체

# 테스트
cargo test --workspace

# 배포 검증
cargo publish -p oxios --dry-run              # 바이너리 패키징
cargo publish -p oxios-bench --dry-run        # 벤치마크 패키징

# 프론트엔드
cd web && bun install && bun run build        # 빌드 확인

# 수동 E2E
oxios --foreground                            # 데몬 시작
# → http://localhost:7878 접속 → 웹 UI 렌더링 → 채팅
# → oxios chat                                 # CLI 인터페이스
```

## Impact Analysis

### 의존성 그래프 단순화

```
Before:                              After:
  oxios binary                        oxios binary
  ├── oxios-web (crate)               ├── api (module, 같은 크레이트)
  │   ├── oxios-gateway               ├── channels (module, 같은 크레이트)
  │   ├── oxios-kernel                │   ├── cli
  │   └── oxi-sdk                     │   └── telegram
  ├── oxios-cli (crate)               ├── oxios-kernel (crate)
  │   └── oxios-gateway               ├── oxios-gateway (crate)
  ├── oxios-telegram (crate)          └── oxi-sdk
  │   └── oxios-gateway
  ├── oxios-kernel
  ├── oxios-gateway
  └── oxi-sdk
```

크레이트 수: 12 → 9 (7 라이브러리 + 바이너리 + bench)

### 크기 변화

| 항목 | Before | After |
|------|--------|-------|
| `src/` (binary) | 5.6K LOC (8 files) | ~20K LOC (~70 files) |
| Workspace members | 11 + binary | 7 + binary + bench |
| crates.io 배포 대상 | 7 (CI) + 5 (수동, 정체) | 9 (CI 전 자동) |

### 호환성

- **KernelHandle API**: 변경 없음. 모든 라이브러리 크레이트가 그대로 유지됨.
- **Surface/Channel trait**: 변경 없음. `oxios-gateway`에 정의됨.
- **Web API 엔드포인트**: 변경 없음. 모든 라우트가 그대로 이동됨.
- **rust-embed 동작**: 변경 없음. `#[folder = "web/dist/"]` 경로가 루트 이동 후에도 동일.
- **Config 파일 (`~/.oxios/config.toml`)**: 변경 없음.
- **`cargo install oxios`**: 여전히 동작. optional dep가 줄어 컴파일 시간 감소 기대.

### 위험

| 위험 | 완화 |
|------|------|
| 대량 파일 이동으로 git history 단절 | `git mv` 사용, `git log --follow`로 추적 가능 |
| Import 경로 누락 | Phase 2-3 통합 진행, `cargo check --all-features` 전수 검사 |
| CI publish 순서 오류 | publish.yml WAIT 매핑 + `working-directory` 분기 |
| oxi-sdk 버전 충돌 잔여 | 동기화 대상 12→9로 감소. 커널 재배포 시 워크스페이스 oxi-sdk 버전 확인 필요 |

## Alternatives Considered

### A. 현상 유지 (별도 크레이트)

**기각.** oxi-sdk 버전 충돌이 반복적으로 발생하며, 재사용 불가능한 코드를 별도
크레이트로 유지하는 비용이 이점을 초과한다.

### B. oxios-web만 바이너리로, CLI/Telegram은 별도 크레이트 유지

**기각.** 900 LOC짜리 크레이트 2개를 유지하는 것은 오버엔지니어링이다. Feature-gated
module로 동일한 격리를 달성할 수 있다.

### C. oxios-web의 Rust 코드를 oxios-kernel에 통합

**기각.** 커널은 전송 계층 무관(transport-agnostic)해야 한다. HTTP (axum, serde) 의존성이
커널에 들어가면 단일 책임 원칙 위반이다. AGENTS.md: "Kernel is intentionally monolithic" —
이는 *비즈니스 로직*의 통합을 의미하며, HTTP 계층 포함이 아니다.

## Out of Scope (별도 RFC)

### rust-embed 제거

현재 `plugin.rs`의 `EmbeddedAssets`는 `web/dist/`를 컴파일 타임에 임베드한다.
이는 런타임 GitHub Releases 다운로드의 폴백이다. 제거 시:

- 바이너리 크기 감소 (~20MB)
- `ActiveWebDist``None`일 때 503 에러로 동작 변경
- crates.io 배포 시 TS 에셋 번들 문제 해결

이는 **런타임 동작 변경**이므로 구조 재편과 분리하여 별도 RFC로 다룬다.

## Open Questions

1. **바이너리 crates.io 배포 시 `web/dist/` 포함 여부.** rust-embed가 `web/dist/`   참조하므로, `cargo publish` 시 이 디렉토리가 존재해야 컴파일 가능. 하지만
   `web/dist/``.gitignore`에 있으므로 git-tracked 파일만 포함하는 `cargo publish`에서
   자동 제외됨. 빌드 시 `web/dist/`가 없으면 rust-embed가 빈 디렉토리를 임베드하는지
   확인 필요 (별도 테스트).

2. **`share/knowledge/` 서빙 경로.** files.md 정적 앱이 `share/knowledge/`로 이동한 후,
   런타임에 어떤 경로에서 서빙하는가? 현재 `/knowledge/` prefix로 서빙되는데, 이 경로가
   `ActiveWebDist` 기반인지 별도 파일시스템 경로인지 확인 필요.

3. **`oxios-bench` 워크스페이스 디렉토리명.** 현재 `benchmarks/`이지만 Cargo 관례는
   `benches/`. 이 RFC와 무관하게 결정 가능.