oxibrain × oxios, 분리되는 미래
oxi 생태계 해부 06장에서 oxibrain이 지금 oxios에 어떻게 붙어있는지는 이미 봤습니다 — BrainConnection 패턴, ledger/projection 구조, RFC-047이 지운 18,075줄까지. 이 페이지는 그다음 질문에 답합니다. 지금 진행 중인 분리 작업이 다 끝나면, 그러니까 oxios와 oxibrain이 완전히 다른 저장소·다른 배포 주기를 가진 두 개의 독립 제품이 되면, 그 구조는 정확히 어떤 모양일까. 이미 코드가 가리키고 있는 방향을 Phase 1부터 4까지 순서대로 따라가 봅니다.
지금은 이렇다 (요약만)
자세한 현재 통합 구조 — BrainConnection 패턴, 원장/프로젝션 아키텍처, RFC-047이 무엇을 지웠는지 — 은 oxi 생태계 해부 06장에서 이미 다뤘습니다. 여기서는 딱 한 가지만 확인하고 넘어갑니다 — oxios가 실제로 oxibrain에 요구하는 표면이 얼마나 작은가. 이 "작음"이 바로 다음 장의 분리 가능성 논리로 그대로 이어집니다.
| BrainClient 메서드 | 용도 |
|---|---|
| search | hybrid / lexical / semantic / graph / community 검색 |
| recall | 에이전트 turn 컨텍스트 조립 — 실제로 가장 많이 불리는 호출 |
| get_entity | 엔티티 belief + 이웃 조회 |
| ingest | 에피소드 기록, episode id 반환 |
| declare | LLM 호출 없이 결정적으로 쓰기 |
| timeline | 엔티티 belief의 시간 범위 조회 |
| stats · why · contradictions · ping | 스페이스 카운트 · provenance · 모순 탐지 · keepalive |
oxibrain-client::BrainClient의 이 8개 메서드뿐입니다 — 전부
call_tool 위에 얹힌 얇은 wrapper. EmbeddingPort · LlmPort ·
TokenizerPort · ClockPort · RerankPort는 oxibrain 내부
구현체(oxibrain-embed-local, oxibrain-llm-http/-local)가 채택하는 트레이트고, oxios 코드베이스
전체를 grep해도 이 트레이트들을 참조하는 곳은 0건입니다. 즉 oxios와 oxibrain의 접점은 처음부터
"MCP tool surface" 하나 — JSON-RPC 메시지 송수신으로 완전히 캡슐화돼 있었습니다.
왜 이미 분리 가능한가
"분리"라고 하면 보통 지금부터 코드를 새로 잘라내야 할 것 같지만, 실제로 oxibrain 코드베이스를 열어보면 이미 3개 레이어로 깔끔하게 나뉘어 있습니다. 아래 4가지가 그 근거입니다 — 전부 지금 존재하는 코드에서 그대로 인용한 사실이지, 앞으로 만들 계획이 아닙니다.
트레이트가 트레이트일 뿐이다
EmbeddingPort·LlmPort·RerankPort·TokenizerPort·
ClockPort 5개가 전부 순수 인터페이스입니다. 구현은 oxibrain 바깥 어댑터 크레이트
(embed-local, llm-http, llm-local)가 갖고, 이 트레이트를 쓰는 쪽은 항상 어댑터를 주입받을 뿐 —
여러 클라이언트가 같은 백엔드를 공유할 수 있는 형태가 이미 여기서 만들어집니다.
pub trait EmbeddingPort: Send + Sync { fn dim(&self) -> usize; fn embed(&self, texts: &[&str]) -> Result<Vec<Vec<f32>>, BrainError>; }
이미 in-process를 안 쓴다
BrainClient는 Arc도 Mutex도, Brain::open의
in-process trait impl도 들고 있지 않습니다. 라이브러리 doc comment가 이걸 직접 못박습니다 —
embedded 모드와 daemon 모드가 같은 Brain 트레이트를 본다고요. 소비자가 토폴로지를 바꾸는 건
함수 하나 스왑하는 것과 같습니다.
Brain::open to
BrainClient::connect." — 프로세스 경계 너머 어떤 클라이언트도 이 client 하나로
똑같이 붙을 수 있습니다. 모바일 앱, WASM 포팅, 별도 CLI — transport가 socket → websocket → https로
바뀌어도 client API는 그대로입니다.
process 경계가 이미 1급 시민이다
같은 Brain facade를 serve_stdio·serve_socket·serve_socket_auth·
serve_http 4가지 transport로 동시에 노출합니다. 그리고 serve_socket_auth는
이미 토큰 인증 프로토콜을 정의해뒀습니다 — 데몬 모드로 완전히 갈아타도 인증 게이트가 이미 준비돼
있다는 뜻입니다.
// 연결 첫 메시지로 인증 토큰을 보낸다 (server.rs:1181-1190) {"jsonrpc":"2.0","id":1,"method":"auth", "params":{"token":"<secret>"}} // 검증 성공 시 scope가 부여된 BrainServer가 이후 세션을 서빙
oxios web과 동급의 독립 프론트엔드
React 19 + Vite 7 + Tailwind v4로 만들어진 별도 SPA입니다. oxios의 web/과 모놀리식
결합이 아니라, serve_http가 ui_dir 파라미터로 이 빌드 결과물을 정적
서빙하도록 이미 배선돼 있습니다 — oxibrain serve --http 127.0.0.1:7878 --ui-dir
apps/brain-ui/dist 한 줄이면 데몬 하나가 UI까지 통째로 호스팅합니다.
"분리 완성"이란 정확히 뭘 의미하나
여기서부터는 추론입니다 — 지금 코드베이스가 가리키는 방향의
끝점을 그린 것이지, 이미 존재하는 상태가 아닙니다. 근거는 RFC-047(진행 중)과 oxibrain
DESIGN §4.3·§11.2·§12·§15가 동시에 수렴하는 지점입니다.
oxibrain은 독립 GitHub 저장소의 standalone server/daemon이 되고, oxios는 그 클라이언트 중
하나가 됩니다. 두 프로젝트 사이에 공유되는 코드는 오직 oxibrain-client crate
하나뿐이며, 이건 crates.io에 0.1.0으로 publish돼 양쪽 저장소 모두 version =
"0.1" 의존으로 들어갑니다. oxibrain/Cargo.toml은 이미
repository = "github.com/a7garden/oxibrain"로 이 의향을 명시하고 있습니다.
BrainClient를 쓰는 여러 클라이언트 중 하나입니다. oxibrain은 3개 transport와 brain-ui를 함께 호스팅하는 단일 daemon 하나가 됩니다.데이터 흐름 — "에이전트 turn이 recall 한 번"
토폴로지가 바뀌어도 실제 호출 시퀀스는 지금과 거의 같습니다. 다른 건 소켓 경로가 로컬 파일에서 네트워크 주소로 바뀔 수 있다는 것 뿐입니다.
- oxios의 web/CLI 채널이 사용자 입력을 받는다.
OxiosEngine이AgentRuntime::execute를 부른다.AgentRuntime이KernelHandle.brain.recall(query, budget)을 호출한다.BrainApi→BrainConnection→BrainClient::call_tool_json("recall", …)이 소켓(또는 HTTP)으로 JSON-RPC 요청을 보낸다.oxibrain-mcp가 요청을 받아BrainServer::recall로 dispatch한다.BrainServer가 query를 임베딩하고 hybrid search(HNSW + FTS + 그래프 + 커뮤니티)한 뒤, token budget으로 잘라 결과를 되돌린다.- 같은 연결의 다음 줄로 응답이 돌아오고,
assemble_context_text가 텍스트로 조립해 agent prompt에 주입한다.
전부 단일 연결의 왕복 한 번 — TCP 커넥션을 새로 열지 않고, 늘어나는 비용은 오직 직렬화뿐입니다.
마이그레이션 로드맵 — Phase 1 → 4
네 단계로 나눴지만, 순서대로 하나씩 "시작"하는 계획이 아닙니다 — Phase 1은 이미 끝났고, Phase 2·3은 이미 절반쯤 가용한 상태에서 마지막 스위치만 남아 있습니다. 진행률을 먼저 한눈에 보고, 아래에서 단계별로 뜯어봅니다.
의존 → 2부분 가용stdio MCP
client → 3진행 중standalone
HTTP daemon → 4미착수marketplace ·
multi-tenant
oxios-memory의 ports-only 의존
oxios-memory 18,075줄이 통째로 삭제되고 oxios-kernel/src/brain/의 얇은
BrainConnection으로 대체된 시점에 이미 끝난 단계입니다. 다만 완전히 깔끔하진 않습니다 —
SONA(궤적 패턴 엔진)와 임베딩 트레이트는 커널 내부로 재흡수됐는데, 이 커널 내부 트레이트와
oxibrain-ports의 트레이트는 이름은 비슷해도 서로 다른 타입입니다.
// oxios-kernel/src/embedding.rs:2-6 //! Re-homed from `oxios-memory` (RFC-047): the traits, TF-IDF provider, //! `TextVector`, and the f32 cosine helpers used by them now live in the //! kernel. The API and GGUF providers are submodules.
커널 쪽 trait은 SONA 같은 kernel-local 소비자가 쓰고, oxibrain-ports 쪽은 oxibrain 백엔드가 쓰는
의도적 분기입니다. 완전히 하나로 합칠 필요는 없지만, 합치고 싶다면 oxibrain의
Brain::with_llm처럼 port를 인자로 받는 생성자 시그니처를 커널 쪽도 채택하는 식으로
점진적으로 좁힐 수 있습니다.
oxibrain-mcp stdio 노출 + oxios는 stdio MCP client
재료는 이미 양쪽에 다 있습니다. oxibrain-mcp는 serve_stdio를 export하고,
oxios는 별도 oxios-mcp crate로 stdio MCP client 능력을 이미 갖고 있습니다 — 워크스페이스
멤버 목록에 이미 들어있는 크레이트입니다. 즉 oxios는 이미 MCP client로 oxibrain을 붙일 능력이
있고, 남은 건 배선뿐입니다.
이 단계의 의미는 BrainConnection이 Unix 소켓 대신 oxios-mcp의 stdio
transport로 oxibrain-mcp::serve_stdio에 붙는 dual-topology 모드입니다. 사용자가
oxibrain serve --stdio로 띄운 서브프로세스를 oxios가 supervise합니다. 장점은 소켓 경로
권한 설정이 사라지고 OS 프로세스 격리로 신뢰가 자동 보장된다는 것, 단점은 child 프로세스 생명주기
관리가 새로 추가된다는 것입니다.
oxibrain standalone daemon + oxios는 HTTP client
oxios의 [brain] 설정은 이미 daemon 토폴로지를 정면으로 가리키고 있습니다 — path
의존만 crates.io version 의존으로 바꾸면 1차 완성입니다.
# oxios/share/default-config.toml:232-239 # oxios delegates all agent memory to the standalone oxibrain daemon over a # Unix-domain socket. When the daemon is unreachable, memory operations # degrade gracefully (return empty) and agent turns complete normally. [brain] enabled = true # socket_path = "" # Empty = ~/.oxi/brain/oxibrain.sock space = "personal"
다음은 HTTP transport 진입입니다. oxibrain-mcp::serve_http는 이미 loopback HTTP
listener를 갖고 있으니, oxios가 --brain-transport=http --brain-url=http://127.0.0.1:7878
같은 옵션을 받고 BrainClient가 transport를 generic화해 소켓/HTTP 양쪽을 같은 API로
처리하면 됩니다. 이 시점부터 socket → http 마이그레이션은 설정 한 줄입니다.
marketplace / multi-tenant
oxibrain-mcp는 이미 토큰 인증과 Scope를 강제합니다(02장 참고). 이 위에 올라갈 것은
새 아키텍처가 아니라 운영 계층입니다.
$ oxibrain token issue --space=acme --caps=Read,Ingest,Write --ttl=90d # crates/oxibrain-cli/src/cmd/token.rs — 이미 존재하는 서브커맨드
토큰 스토어는 이미 SQLite 안에 있고, 클라이언트는 BrainClient::connect_with_token(path,
token) 한 줄로 tenant scope를 얻습니다. 이게 갖춰지면 열리는 시나리오는: 여러 oxios
인스턴스가 각자의 토큰으로 같은 oxibrain 데몬에 붙고, 데몬은 space 단위로 데이터를 격리하고,
클라우드 호스팅은 oxibrain serve --http 0.0.0.0:443 --require-token --tls-cert=… +
리버스 프록시(Caddy/Traefik) 조합으로 끝납니다. oxibrain-cli의 서브커맨드 목록
(import_oxios, reextract, reproject, eval,
doctor, gate, token)이 이미 SaaS 운영에 필요한 도구의
90%를 갖추고 있습니다.
비용과 이점
분리는 공짜가 아닙니다. 각 이점 뒤에는 정확히 대응하는 비용이 하나씩 붙어있고, 그 쌍을 같이 봐야 "그래서 할 가치가 있나"를 제대로 판단할 수 있습니다.
가벼워진다
LOC 절감 vs latencyRFC-047 한 번으로 oxios에서 ~13,600 LOC가 사라졌습니다. crates.io 배포 표면에서
oxios-memory가 없어지니 컴파일 시간이 줄고 의존 그래프가 단순해집니다. oxibrain-client
의 round-trip 테스트도 oxios kernel 전체를 띄우지 않고 client 계약만 검증하니, 두 저장소의 CI가
각자 빨라집니다.
대신 in-process trait 호출(대략 나노초 단위)이 Unix 소켓 JSON-RPC 왕복(보통 100~500
마이크로초)으로 바뀝니다. recall·search·ingest가 turn마다 소켓 한 번씩이면 누적 비용은 밀리초
단위로 쌓입니다. 다만 BrainServer::recall 안에서 어차피 sqlite-vec + FTS + 그래프까지
도는 걸 감안하면, 외부화로 순수하게 추가된 비용은 IPC 직렬화뿐입니다.
독립 제품으로 출시된다
제품화 vs 운영 이중화apps/brain-ui는 이미 1st-class React 프론트엔드고, oxibrain-cli는 24개
서브커맨드를 갖춘 완전한 CLI입니다. SaaS·on-prem·데스크톱 embed·모바일 backend, 어느 형태로든 출시가
가능합니다. LLM/임베딩 어댑터(oxibrain-llm-http, -llm-local)도 이미 분리돼
있어서, oxios의 oxicode-sdk 업그레이드 주기와 무관하게 백엔드를 교체할 수 있습니다.
대신 프로세스가 둘이 됩니다. 두 프로세스의 lifecycle 관리, 두 데몬의 healthcheck, 두 로그를
상관관계 분석해야 하는 부담, 두 릴리스의 버전 매트릭스까지 — 전부 사용자 몫입니다.
BrainConnection의 degradation contract(데몬이 죽으면 빈 값 반환, agent turn은 정상
종료)가 1차 방어선이긴 하지만, oxibrain 데몬 자체를 launchd/systemd로 따로 관리해야 하는 건
똑같습니다.
멀티 클라이언트로 확장된다
공유 서비스 vs 인증·일관성 비용BrainClient는 transport-agnostic이라 socket → websocket → https로 자라날 수 있고,
oximemo·oxiline 같은 자매 프로젝트가 같은 데몬을 동시에 씁니다. Phase 4의 토큰 발급 체계
(connect_with_token)가 이미 구현돼 있는 덕분입니다.
대신 in-process 시절엔 OS 프로세스 격리가 곧 신뢰였던 게, 데몬 모드에선
--require-token이나 파일시스템 권한에 의존하는 구조로 바뀝니다. 토큰 로테이션·감사는
별도 작업이 필요합니다. 그리고 oxios가 "최근 N건 조회 → 요약 → 재기록" 같은 read-modify-write를
원할 때, lock이 소켓 너머로 옮겨가면서 round-trip이 늘어납니다 — RFC-047이 명시한 "split-brain
방지"가 정확히 이 지점을 겨냥한 조항입니다.
oxibrain import-oxios --source ~/.oxios/workspace/memory.db --space
personal → reextract → reproject 3단계 마이그레이션을 한 번은
거쳐야 합니다. 데이터가 자동으로 따라오지 않는다는 뜻입니다.
정리
분리 이유는 단일 책임과 출시 경로입니다 — oxios는 에이전트 런타임 + 채널의 OS, oxibrain은
기억 substrate. 분리 방법은 ports/client/mcp 3-레이어로 이미 잘려 있고, oxios는
oxibrain-client 딱 하나만 의존합니다. 완성됐을 때 모습은 oxibrain 하나의 standalone
daemon이 stdio·Unix소켓·HTTP를 동시에 열고 brain-ui까지 스스로 서빙하며, oxios·oximemo·oxiline·
모바일이 같은 BrainClient로 나란히 접속하는 그림입니다. latency·운영 부담·인증이라는
비용은 분명히 있지만, degradation contract(데몬이 죽어도 agent turn은 정상 종료)가 1차
안전망이고, Phase 1은 이미 끝났고 2·3은 마지막 스위치만 남았습니다.