Sari - Local Search MCP Server
Project description
๐งโโ๏ธ Sari (์ฌ๋ฆฌ)
"์ ์ ๋ด ๋ง ์ข ๋ค์ด๋ณด๊ฒ๋... ์๋ค์ ์์ค์ฝ๋๊ฐ ์ง์ฅ์ ๋น๋ช ์ ์ง๋ฅด๋ ์๋ฆฌ๋ฅผ!" (Stay awhile and listen...)
**์ฌ๋ฆฌ(Sari)**๋ ์ธ๊ณต์ง๋ฅ(AI) ์น๊ตฌ๋ค์ด ์ฌ๋ฌ๋ถ์ ๋ณต์กํ๊ณ ๊ฑฐ๋ํ ์ฝ๋๋ฅผ ์์ฃผ ์ฝ๊ณ ๋น ๋ฅด๊ฒ ์ดํดํ ์ ์๋๋ก ๋์์ฃผ๋ **'ํธ๋ผ๋๋ฆผ์ ์์ ๊ธฐ๋ก๊ด'**์ด์์.
์ฌ๋ฆฌ ์ ์๋๋ง ๊ณ์๋ฉด ์๋ฌด๋ฆฌ ์ฝํ๊ณ ์คํจ ์ฝ๋๋ผ๋ AI๊ฐ ๊ธธ์ ์์ง ์๊ณ ํ์ํ ํด๋์ค๋ฅผ 0.1์ด ๋ง์ ์ฐพ์๋ผ ์ ์๋ต๋๋ค.
ํธ๋ผ๋๋ฆผ์ ์ด๋ถ์ด ๊บผ์ง์ง ์๋ ํ, ์ธ๋ฑ์ฑ ๋๋ฝ์ด๋ผ๋ ํผ๋์ ๋น๋ช
์ ๋ค๋ฆฌ์ง ์๊ฒ ๋ ๊ฑฐ์์. ๐ (์ ์๋์ด ์งํก์ด๋ก ๊ธธ์ ์์ฃผ ์์ธํ ์๋ดํด์ฃผ์ ๋ต๋๋ค.)
๐ง ์ฌ๋ฆฌ ์ ์๋์ ๋๊ตฌ์ธ๊ฐ์? (์ฝ๊ฒ ์ดํดํ๊ธฐ)
์ฌ๋ฌ๋ถ์ ์ปดํจํฐ์๋ ์์ฃผ ๋ง์ ์ฝ๋ ํ์ผ์ด ์์ด์. ๋๋ํ **AI ์น๊ตฌ(Codex, Claude, Cursor, Gemini ๋ฑ)**์๊ฒ ์ฝ๋๋ฅผ ์ง๋ฌ๋ผ๊ณ ํ๋ฉด ๊ฐ๋ ์ด๋ฐ ๋ง์ ํ ๊ฑฐ์์. "๋ฏธ์ํด, ํ์ผ์ด ๋๋ฌด ๋ง์์ ์ด๋์ ๋ญ๊ฐ ์๋์ง ๋ชจ๋ฅด๊ฒ ์ด!"
๊ทธ๋ ๋ฐ๋ก ์ฌ๋ฆฌ ์ ์๋์ด ํธ๋ฆฌ์คํธ๋ผ ์ด๋๊ฐ์์ ๋ง๋ฒ์ฒ๋ผ ๋ํ๋ฉ๋๋ค!
- ์ง๋ ํ ์ฌ์: ์ฌ๋ฆฌ ์ ์๋์ ์ฌ๋ฌ๋ถ์ ๋ชจ๋ ์ฝ๋๋ฅผ ๋ฏธ๋ฆฌ ๋ค ์ฝ์ด๋๊ณ , ๋๊ฐ ์ด๋ ์ง์ฅ ๊ตฌ์์ ์ฌ๋์ง(์ด๋ค ํจ์๊ฐ ์ด๋ค ํ์ผ์ ์๋์ง) ์์ฃผ ์์ธํ **'ํธ๋ผ๋๋ฆผ ์ฅ๋ถ'**๋ฅผ ๋ง๋ค์ด๋ฌ์. (๋์ด ์นจ์นจํ์ ๋ ์ ๊ท์์ ๊ธฐ๊ฐ ๋งํ๊ฒ ๋ณด์ญ๋๋ค.)
- AI์ ๊ธธ์ก์ด: AI ์น๊ตฌ๊ฐ "์ด ํ๋ก์ ํธ์์ ํ์๊ฐ์
์ ์ด๋ป๊ฒ ํด?"๋ผ๊ณ ๋ฌผ์ด๋ณด๋ฉด, ์ฌ๋ฆฌ ์ ์๋์ด ์งํก์ด๋ฅผ ์ง๊ณ ์ฅ๋ถ๋ฅผ ์ฅ ๋ณด๊ณ ๋ "3๋ฒ ์ ๋ฐ ์๋, ๋์๋ธ๋ก์ ๊ผฌ๋ฆฌ ์์ ์๋
user.pyํ์ผ์ ๋ณด๊ฒ๋! ์ฃผ์ ์ข ๋๋ฐ๋ก ๋ฌ์ง ๊ทธ๋ฌ๋..."๋ผ๊ณ ๊พธ์ง์ผ๋ฉฐ ์๋ ค์ค๋๋ค. - MCP(Model Context Protocol): ์ด๊ฑด AI ์น๊ตฌ์ ์ฌ๋ฆฌ ์ ์๋์ด ์๋ก ๋ํํ ๋ ์ฐ๋ 'ํธ๋ผ๋๋ฆผ ํต์ญ๊ธฐ' ๊ฐ์ ๊ฑฐ์์. ์ด ํต์ญ๊ธฐ ๋๋ถ์ ์ฌ๋ฆฌ ์ ์๋์ ์ธ์์ ๋ชจ๋ ์ต์ AI์ ๋ํํ ์ ์๋ต๋๋ค! (๊ณ ๋์ด๋ ๋ชฐ๋ผ๋ Python์ ๊ฟฐ๊ณ ๊ณ์์ฃ .) ๐ค
๐ ์ฌ๋ฆฌ ์ ์๋์ ํน๋ณํ ๋ฅ๋ ฅ
- โก ์ฐจ์๋ฌธ ๊ฒ์: ์๋ง ์ค์ ์ฝ๋๋ ์์๊ฐ์ ์ฝ์ด์ ํ์ํ ๋ถ๋ถ๋ง ๊ณจ๋ผ๋ด์. (TP ํ๋ ์๋๋ณด๋ค ๋น ๋ฆ ๋๋ค.)
- ๐ง ์ฝ๋ ์ฌ๋ น์ : ๋จ์ํ ๊ธ์๋ง ์ฐพ๋ ๊ฒ ์๋๋ผ, ์ด๊ฒ 'ํจ์'์ธ์ง 'ํด๋์ค'์ธ์ง ์ฝ๋์ ์ํผ(AST)์ ์ฝ์ด๋ ๋๋ค.
- ๐ ์ฒ ํต ๋ณด์: ๋ชจ๋ ๊ณต๋ถ๋ ์ฌ๋ฌ๋ถ์ ์ปดํจํฐ ์์์๋ง ํด์. ์ฝ๋๊ฐ ์ฑ์ญ(์ธํฐ๋ท) ๋ฐ์ผ๋ก ์ ๋ ๋๊ฐ์ง ์์ผ๋ ์์ฌํ์ธ์! ์ง์ฅ์ ์ ๋ง๋ ์ฌ๋ฌ๋ถ์ ์์ค์ฝ๋๋ ๋ชป ํ์ณ๊ฐ๋๋ค. ๐ก๏ธ
- ๐ป ํฌ๋ช ๋งํ : ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์กฐ์ฉํ ์ผํ๋ฉฐ ์ฌ๋ฌ๋ถ์ด ์ฝ๋๋ฅผ ๊ณ ์น ๋๋ง๋ค ์ฅ๋ถ๋ฅผ ์์์ ์ ๋ฐ์ดํธํด์. (๊ฐ๋ ๊ณ์ ์ง ํ์ธํ์ง ์์ผ๋ฉด ์ญ์ญํดํ์ญ๋๋ค.)
๐ ์ฑ์ญ ์ํ ์ฃผ๋ฌธ (์ค์น ๋ฐฉ๋ฒ - Installation)
์ค์:
deckard๋ชจ๋/์ํธ๋ฆฌํฌ์ธํธ๋ ํธํ์ฉ์ผ๋ก๋ง ์ ์ง๋ฉ๋๋ค.
์์ผ๋ก๋ Sari ์ด๋ฆ์ ์ฌ์ฉํด ์ฃผ์ธ์. (ํฅํ ๋ฒ์ ์์ ์ ๊ฑฐ ์์ )๊ฐ๋ฐ์ ์ฐธ๊ณ : ๋ด๋ถ ๋ชจ๋์
sari.core,sari.mcp๋ค์์คํ์ด์ค๋ก ์ ๊ณต๋ฉ๋๋ค.
์ถฉ๋ ๋ฐฉ์ง๋ฅผ ์ํดapp,mcp๊ฐ์ ์ต์์ ํจํค์ง๋ ๋ฐฐํฌ๋ณธ์ ํฌํจ๋์ง ์์ต๋๋ค.
์ค์น ๋ฐฉ์์ ๋ ๊ฐ์ง์ ๋๋ค.
- ์ค์ ๋ง ์ถ๊ฐํ๋ฉด ์๋ ์ค์น (๊ถ์ฅ)
- ์ง์ ์ค์น (์คํ๋ผ์ธ/์ ํ ํ๊ฒฝ์ฉ)
์ค์น ์์ ์ฑ ๊ธฐ์ค (KPI)
- ์คํ๋ผ์ธ/๋ก์ปฌ ์์ค/๋ค๋ฅธ workspace ์ฌํ ์ฑ๊ณต๋ฅ : 3/3
์๋ ์ค์น ์กฐ๊ฑด ์์ฝ
DECKARD_ENGINE_MODE=embedded+DECKARD_ENGINE_AUTO_INSTALL=1+ ๋คํธ์ํฌ/pip ๊ฐ๋ฅ
โ 1) ์ค์ ๋ง ์ถ๊ฐํ๋ฉด ์๋ ์ค์น (๊ถ์ฅ)
MCP ์ค์ ํ์ผ์ ์๋ ๋ธ๋ก์ ์ง์ ์ถ๊ฐํ๋ฉด, ์คํ ์ Sari๊ฐ ์๋ ์ค์น๋ฉ๋๋ค.
[mcp_servers.sari]
command = "bash"
args = ["-lc", "curl -fsSL https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python3 - -y; exec ~/.local/share/sari/bootstrap.sh --transport stdio"]
env = { DECKARD_WORKSPACE_ROOT = "/path/to/workspace", DECKARD_RESPONSE_COMPACT = "1" }
startup_timeout_sec = 60
๐งฉ ์ค์ /์ค์น ์์ธ ๊ฐ์ด๋ (์ด๋ณด์์ฉ / ๊ณ ๊ธ์์ฉ)
โ ์ด๋ณด์์ฉ (๊ถ์ฅ ๊ฒฝ๋ก)
1) ์ค์น ๋ฐฉ์ ์ ํ ๊ฐ์ด๋
A. ์ค์ ๋ง ์ถ๊ฐ(๊ถ์ฅ)
MCP ์ค์ ์ bootstrap.sh ์คํ ๋ธ๋ก์ ์ถ๊ฐํ๋ฉด, ์คํ ์ ์๋ ์ค์น๋ฉ๋๋ค.
B. ์คํ๋ผ์ธ/๊ณ ์ ์ค์น
๋คํธ์ํฌ๊ฐ ๋ถ๊ฐํ ํ๊ฒฝ์ด๋ฉด ์ด๋ฏธ ์ค์น๋ bootstrap.sh ๊ฒฝ๋ก๋ฅผ ์ง์ ์ง์ ํ์ธ์.
๋กค๋ฐฑ(SQLite) ๊ฒฝ๊ณ
SQLite ๋ชจ๋๋ก ๋กค๋ฐฑํ ๊ฒฝ์ฐ FTS ์ฌ๋น๋๊ฐ ํ์ํ ์ ์์ผ๋ฉฐ, ์๋ฃ ์ ๊น์ง ๊ฒ์ ํ์ง์ด ์ ํ๋ ์ ์์ต๋๋ค.
2) MCP ์ค์ ํ์ผ ์์น (์ฑ๋ณ)
Codex / Gemini
<workspace>/.codex/config.toml
Claude Desktop
claude_desktop_config.json
Cursor
์ฑ Settings > MCP ๋ฉ๋ด
3) MCP ์ค์ ํ ํ๋ฆฟ (TOML)
[mcp_servers.sari]
command = "bash"
args = ["-lc", "curl -fsSL https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python3 - -y; exec ~/.local/share/sari/bootstrap.sh --transport stdio"]
env = {
DECKARD_WORKSPACE_ROOT = "/path/to/workspace",
DECKARD_RESPONSE_COMPACT = "1",
DECKARD_ENGINE_MODE = "embedded",
DECKARD_ENGINE_TOKENIZER = "auto",
DECKARD_ENGINE_AUTO_INSTALL = "1"
}
startup_timeout_sec = 60
4) MCP ์ค์ ํ ํ๋ฆฟ (JSON)
{
"mcpServers": {
"sari": {
"command": "bash",
"args": [
"-lc",
"curl -fsSL https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python3 - -y; exec ~/.local/share/sari/bootstrap.sh --transport stdio"
],
"env": {
"DECKARD_WORKSPACE_ROOT": "/path/to/workspace",
"DECKARD_RESPONSE_COMPACT": "1",
"DECKARD_ENGINE_MODE": "embedded",
"DECKARD_ENGINE_TOKENIZER": "auto",
"DECKARD_ENGINE_AUTO_INSTALL": "1"
},
"startup_timeout_sec": 60
}
}
}
5) env ์ต์ ์ค๋ช (ํต์ฌ)
DECKARD_WORKSPACE_ROOT
์ํฌ์คํ์ด์ค ๋ฃจํธ. ๊ฐ์ฅ ์ค์ํ ์ต์
.
DECKARD_ENGINE_MODE
์์ง ๋ชจ๋ ์ ํ. embedded|sqlite (๊ธฐ๋ณธ: embedded)
DECKARD_RESPONSE_COMPACT
PACK1 ์๋ต ์์ถ(๊ธฐ๋ณธ 1).
DECKARD_ENGINE_TOKENIZER
auto|cjk|latin ์ ํ.
DECKARD_ENGINE_AUTO_INSTALL
1์ด๋ฉด ์ฒซ ๊ฒ์/์ฌ๋น๋ ์ ์์ง ์๋ ์ค์น.
DECKARD_READ_MAX_BYTES
read_file ์๋ต ์ต๋ ๋ฐ์ดํธ ์ ์ ํ (๊ธฐ๋ณธ: 1,048,576 bytes). ํฐ ํ์ผ OOM ๋ฐฉ์ง์ฉ.
DECKARD_READ_POOL_MAX
read ์ ์ฉ ์ปค๋ฅ์
ํ ์ํ (๊ธฐ๋ณธ: 32). ์ด๊ณผ ์ ๊ธฐ๋ณธ read ์ปค๋ฅ์
์ ๊ณต์ .
6) bootstrap.sh ๋จ๋ ์คํ (CLI)
DECKARD_WORKSPACE_ROOT=/path/to/workspace \
DECKARD_ENGINE_MODE=embedded \
DECKARD_ENGINE_TOKENIZER=cjk \
DECKARD_ENGINE_AUTO_INSTALL=1 \
~/.local/share/sari/bootstrap.sh --transport stdio
7) ์คํ๋ผ์ธ/๊ณ ์ ์ค์น ๊ฒฝ๋ก
macOS/Linux
~/.local/share/sari/bootstrap.sh
Windows
%LOCALAPPDATA%\\sari\\bootstrap.bat
8) ๊ฐ์ฅ ํํ ์ค์
workspace-root ๋ฏธ์ง์
ํ ๋๋ ํ ๋ฆฌ ์ ์ฒด๊ฐ ์ธ๋ฑ์ฑ๋ ์ ์์ต๋๋ค. ๋ฐ๋์ ์ง์ ํ์ธ์.
args/env ๋ถ์ผ์น
env๊ฐ ์ฐ์ ์ ์ฉ๋๋ฏ๋ก ๋์ ๋์ผํ๊ฒ ๋ง์ถ์ธ์.
์ค์น๋ณธ/๋ ํฌ ๊ฒฝ๋ก ํผ์ฉ
ํ๋์ ๊ฒฝ๋ก๋ง ์ฌ์ฉํ์ธ์.
๐ ๊ณ ๊ธ์์ฉ (์ปค์คํฐ๋ง์ด์ง)
1) ์์ง/ํ ํฌ๋์ด์ ๊ฐ์ ์ค์
export DECKARD_ENGINE_TOKENIZER=latin
export DECKARD_ENGINE_AUTO_INSTALL=0
export DECKARD_ENGINE_MODE=embedded
2) ์๋ต ํฌ๋งท ๋๋ฒ๊น
export DECKARD_FORMAT=json
export DECKARD_RESPONSE_COMPACT=0
3) ๋ฃจํธ/ํฌํธ/DB ๊ฒฝ๋ก ๊ณ ์
export DECKARD_WORKSPACE_ROOT=/path/to/workspace
export DECKARD_HTTP_API_PORT=7331
export DECKARD_DB_PATH=/absolute/path/to/index.db
4) ๋ฉํฐ ๋ฃจํธ (๊ณ ๊ธ)
export DECKARD_ROOTS_JSON='["/path/a","/path/b"]'
5) ์คํ ์์ (๋จ์ผ ์ปค๋งจ๋)
DECKARD_WORKSPACE_ROOT=/path/to/workspace \
DECKARD_ENGINE_MODE=embedded \
DECKARD_ENGINE_TOKENIZER=cjk \
DECKARD_ENGINE_AUTO_INSTALL=1 \
DECKARD_FORMAT=pack \
~/.local/share/sari/bootstrap.sh --transport stdio
6) ๋ฒ๋ค ํฌ๊ธฐ ์ค์ด๊ธฐ (์ต์ )
์์ง ํ ํฌ๋์ด์ ์ฌ์ ์ OS๋ณ wheel์ด ํจ๊ป ํฌํจ๋ฉ๋๋ค.
๋ฐฐํฌ ํฌ๊ธฐ๋ฅผ ์ค์ด๋ ค๋ฉด ํ์ฌ OS์ ๋ง๋ ๋ฒ๋ค๋ง ๋จ๊ธฐ์ธ์.
./scripts/prune_tokenizer_bundles.sh
Windows:
scripts\prune_tokenizer_bundles.bat
๐ง Engine/Tokenizer ์ต์ (env๋ก ์ฃผ์ )
bootstrap.sh๋ก ํ๋ฐฉ ์ค์นํด๋ env๋ ๊ทธ๋๋ก ์ ์ฉ๋ฉ๋๋ค.
MCP ์ค์ ์ env์ ์๋ ์ต์
์ ์ถ๊ฐํ์ธ์.
๋ชจ๋ ์ฐจ์ด (Embedded vs SQLite)
embedded- Tantivy ๊ธฐ๋ฐ ์์ง ์ฌ์ฉ (๊ฒ์ ํ์ง/์ฑ๋ฅ ์ฐ์ )
- ๋ณ๋ ์์ง ์ค์น ํ์ (์๋ ์ค์น ๊ฐ๋ฅ)
- CJK ํํ์ ๋ถ์์ ๋ฒ๋ค๋ lindera(ipadic) ์ฌ์ ์ ์ฌ์ฉ (์ธ๋ถ ๋ค์ด๋ก๋ ์์)
- ์ธ๋ฑ์ค๋
~/.local/share/sari/index/<roots_hash>์ ๊ด๋ฆฌ
sqlite- SQLite FTS/LIKE ๊ธฐ๋ฐ (ํธํ/๋กค๋ฐฑ์ฉ)
- ์์ง ์ค์น ์์ด ๋์
- ๋์ฉ๋/๊ณ ์ ๊ฒ์ ์ฑ๋ฅ์ ์ ํ์
์๋ ์ค์น ๋์ ์กฐ๊ฑด
DECKARD_ENGINE_MODE=embeddedDECKARD_ENGINE_AUTO_INSTALL=1- ๋คํธ์ํฌ ๊ฐ๋ฅ +
pip์ค์น ๊ฐ๋ฅ
์๋ ์ค์น ๋นํ์ฑ/์คํจ ์
- ์คํ๋ผ์ธ ํ๊ฒฝ์ด๊ฑฐ๋
DECKARD_ENGINE_AUTO_INSTALL=0์ธ ๊ฒฝ์ฐ ์๋ ์ค์น๊ฐ ๋์ํ์ง ์์ต๋๋ค. - ์๋ ์ค์น ๋ช
๋ น:
sari --cmd engine install
์ค๋ฅ ๋ฉ์์ง/๋ณต๊ตฌ ์๋ด (๊ณ ์ )
- ์๋ ์ค์น ์คํจ:
ERR_ENGINE_NOT_INSTALLEDโsari --cmd engine install - ์์ง ์ค๋น ์ ๋จ:
ERR_ENGINE_UNAVAILABLEโsari --cmd engine rebuild
์ฃผ์ ์ต์
DECKARD_ENGINE_MODE=embedded|sqlite- ๊ธฐ๋ณธ:
embedded embedded: Tantivy ๊ธฐ๋ฐ ์์งsqlite: SQLite ๊ฒ์ ์์ง(ํธํ/๋กค๋ฐฑ์ฉ)
- ๊ธฐ๋ณธ:
DECKARD_ENGINE_TOKENIZER=auto|cjk|latin- ๊ธฐ๋ณธ:
auto cjk: CJK ํ ํฌ๋์ด์ ๊ฐ์ latin: latin ํ ํฌ๋์ด์ ๊ฐ์
- ๊ธฐ๋ณธ:
DECKARD_ENGINE_AUTO_INSTALL=1|01: ์ฒซ ๊ฒ์/์ฌ๋น๋ ์ ์๋ ์ค์น0: ์๋ ์ค์น ๋นํ์ฑ (์คํ๋ผ์ธ/์ ํ ํ๊ฒฝ)
DECKARD_LINDERA_DICT_PATH=/path/to/dictionary- ํํ์ ์ฌ์ ๊ฒฝ๋ก ๊ฐ์ ์ง์ (ํ์ ์)
DECKARD_READ_MAX_BYTES=0|Nread_file์๋ต ํฌ๊ธฐ ์ ํ.0์ด๋ฉด ์ ํ ์์.- ๊ธฐ๋ณธ:
1048576(์ฝ 1MB)
DECKARD_READ_POOL_MAX=0|N- read ์ ์ฉ ์ปค๋ฅ์
ํ ์ํ.
0์ด๋ฉด ์ ํ ์์. - ๊ธฐ๋ณธ:
32
- read ์ ์ฉ ์ปค๋ฅ์
ํ ์ํ.
์์
env = {
DECKARD_WORKSPACE_ROOT = "/path/to/workspace",
DECKARD_RESPONSE_COMPACT = "1",
DECKARD_ENGINE_MODE = "embedded",
DECKARD_ENGINE_TOKENIZER = "cjk",
DECKARD_ENGINE_AUTO_INSTALL = "1"
}
๐งฐ 2) ์ง์ ์ค์น (์คํ๋ผ์ธ/์ ํ ํ๊ฒฝ์ฉ)
ํฐ๋ฏธ๋(Terminal)์์ ์ง์ ์ค์น๋ ๊ฐ๋ฅํฉ๋๋ค.
# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python3 - -y
# Windows (PowerShell)
irm https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python - -y
๐ ํธ๋ผ๋๋ฆผ์ ์ค์น ๊ณ์ (How it works)
์ฌ๋ฆฌ ์ ์๋์ ์ค์น ๋ง๋ฒ์ ์ด๋ ๊ฒ ๋์ํฉ๋๋ค:
- ์ค์ ๋ง ์ถ๊ฐ โ ์คํ ์ ๋คํธ์ํฌ์์ ์๋ ์ค์น
- ์ค์น ์์น๋ ํญ์ ์ ์ญ ๊ณ ์ (
~/.local/share/sari/%LOCALAPPDATA%\\sari) - ๋ฐ๋ชฌ์ ํญ์ ํ๋๋ก ์ ์ง
์ค์นํ๋ฉด ์ด๋ค ๋ง๋ฒ์ด ์ผ์ด๋๋์?
- ์งํ ์ ์: ์ฌ๋ฆฌ ์ ์๋์ด ์ผํ ๋ ํ์ํ ์ต์ํ์ ๋๊ตฌ(Python ์์ง ๋ฑ)๋ฅผ ์๋์ผ๋ก ์ค๋นํฉ๋๋ค.
- ๋น๋ฐ ๊ฑฐ์ฒ ๋ง๋ จ: ๋์๊ด ์ฃผ์๋ฅผ ๋ง๋ญ๋๋ค. (์ด์ฌ ๋น์ฉ์ ๋ฌด๋ฃ์
๋๋ค.)
- macOS/Linux:
~/.local/share/sari(์ฌ๊ณผ ๋งํฌ๊ฐ ์ฐํ ๋น๋ฐ ์ฐฝ๊ณ ) - Windows:
%LOCALAPPDATA%\sari(์ฐฝ๋ฌธ์ด ๋ฌ๋ฆฐ ๋น๋ฐ ์ฐฝ๊ณ )
- macOS/Linux:
- ํต์ญ๊ธฐ ์ฐ๊ฒฐ: MCP ์ค์ ๋ธ๋ก๋ง ์ถ๊ฐํ๋ฉด ์คํ ์ ์๋์ผ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
์ค์ ์ ์ด๋์ ์จ๊ฒจ์ง๋์? (์๋ ๋ฑ๋ก ๋ฐฉ์)
์ค์ ํ์ผ์ ์๋์ผ๋ก ์์ ํ์ง ์์ต๋๋ค.
Codex/Gemini๋ TOML, Cursor/Claude๋ JSON ํ์์ผ๋ก ๋์ผ ๋ด์ฉ์ ๋ฃ์ด์ฃผ์ธ์.
์ฌ๋ฌ ์ํฌ์คํ์ด์ค๋ฅผ ๋์์? (๋ถ์ ์ ์ ๋๊ฐ)
- ์ค์ ์ ์ํฌ์คํ์ด์ค๋ณ๋ก ๊ฐ์์ ์ด๋ช
์ ๊ฐ์ง๋๋ค.
์: A์์ ์คํ โA/.codex/config.toml์์ฑ (A์ ๊ธฐ๋ก)
B์์ ์คํ โB/.codex/config.toml์์ฑ (B์ ๋ฐ์) - ๋ชธ์ ํ๋, ์งํ๋ ์ฌ๋ฌ ๊ณณ์: ์ฌ๋ฆฌ ์ ์๋์ ํ๋์ ๋ฐ๋ชฌ(Daemon)์ผ๋ก ๋์ํ์ง๋ง, ์ฑ์ญ ๊ณณ๊ณณ์ ๋ถ์ ์ ๋ณด๋ด์ด A์ B ์ํฌ์คํ์ด์ค๋ฅผ ๋์์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค! (์ ์๋์ด ์์ปคํ๋ฆญ์ด๋ผ AB ๋ ๋ค ์ผ๋๋ฉด ๋ ๋ค ์ ์ ์ด ์์งํ์ ๋ค๋ค.)
- ์ฒ ์ ํ ๊ธฐ๋ก ๋ถ๋ฆฌ: A์ ์ฅ๋ถ์ B์ ์ฅ๋ถ๋ ์๋ก ์์ด์ง ์๋๋ก ์๊ฒฉํ ๋ถ๋ฆฌ๋ ์๋(Data Directory)์ ๋ณด๊ด๋ฉ๋๋ค. A์์ ๋์๋ธ๋ก๋ฅผ ๊ฒ์ํ๋๋ฐ B์ ๋ฐ์์ด ํ์ด๋์ค๋ ์ผ์ ์์ผ๋ ์์ฌํ์๊ฒ๋.
๐ช ์ค์น ์ต์ (๋์)
์คํ๋ผ์ธ/์ ํ ํ๊ฒฝ์ฉ
์ค์ ์์ command๋ฅผ ์ค์น๋ณธ bootstrap.sh๋ก ์ง์ ์ง์ ํ๋ฉด ๋คํธ์ํฌ ์์ด ์คํํ ์ ์์ต๋๋ค.
bootstrap ์คํฌ๋ฆฝํธ ์์น
- macOS/Linux:
~/.local/share/sari/bootstrap.sh - Windows:
%LOCALAPPDATA%\\sari\\bootstrap.bat
๐งญ ์ฐจ์๋ฌธ ์ฐ๊ฒฐ ์์น์ ๋์ (์คํ ์์น ์์ฝ)
| ์คํ ์์น (์ฐจ์๋ฌธ ์ฃผ์) | workspace-root๊ฐ ์์ ๋ ์ด๋ช |
|---|---|
| ๋ ํฌ ๋ด๋ถ | ๋ ํฌ ๋๋ ์์ .codex-root๋ฅผ ๊ณ ํฅ์ผ๋ก ์ธ์ |
| ์ํฌ์คํ์ด์ค ๋ฃจํธ | "์ฌ๊ธฐ๊ฐ ๋ด ์ง์ด๊ตฌ๋!" ํ๊ณ ๋ฐ๋ก ์ ์ฐฉ |
ํ ๋๋ ํ ๋ฆฌ (~) |
์ฌ๋ฌ๋ถ์ ์จ ์ง์ ์ด๋ฆผ์ ๋ค ๋ค์ง์ด ๋ด (๊ฐ๋ ฅํ ๋น์ถ์ฒ!) |
โ ๏ธ "์ฑ์ค๋ฌ์ด ํผ์ฉ" ๊ธ์ง ๊ฒฝ๊ณ
command์ ์ค์น๋ณธ๊ณผ ๋ ํฌ ๊ฒฝ๋ก๋ฅผ ์์ด ์ฐ๋ฉด ์ง์ฅ๋ฌธ์ด ์ด๋ฆด ์ ์์ต๋๋ค:
- ์ ๋ฐ์ดํธ ๊ท์น์ด ๋ค์์ผ์ ๊ณ ๋ ๋ฒ์ ์ด ํ์ด๋์ค๊ฑฐ๋,
- ์๋ก ๋ค๋ฅธ ๋ฐ๋ชฌ์ด ๋ํ๋ ํฌํธ 47779๋ฅผ ๋๊ณ '์ฑ์ '์ ๋ฒ์ด๊ฑฐ๋,
- "์ด๋ ์ค์ ์ด ์ง์ง์ธ๊ฐ" ํ๊ณ ์์ ๋ถ์ด์ด ์ผ์ด๋ฉ๋๋ค.
๋ฐ๋ผ์ config์๋ ํญ์ ํ ๊ฒฝ๋ก๋ง ์ ์งํ์ธ์. (1โStep ๋๋ ๊ณ ์ ๋ชจ๋ ์ค ํ๋!)
๐ ์ฑ์ญ์ ์ ์ง๋ณด์ (Update & Recovery)
๐ ๊ฐ์ ์ ๋ฐ์ดํธ ๋ฐ ๋ณต๊ตฌ
๋ง์ฝ ์ค์น ํด๋๊ฐ ์์๋์๊ฑฐ๋, ์ต์ ๋ฒ์ ์ผ๋ก ๊ฐ์ ์ฌ์ค์น๊ฐ ํ์ํ๋ค๋ฉด --update ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ์ธ์.
# ์ค์น๊ฐ ๊ผฌ์๊ฑฐ๋ ์
๋ฐ์ดํธ๊ฐ ํ์ํ ๋
curl -fsSL https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python3 - --update -y
โ ์์ ๊ธฐ๋ก๊ด์ ์ต์ข ์ ๊ฒ (Checklist)
์ค์น ํ ๋ชจ๋ ๊ฒ์ด ์ ์์ธ์ง ํ์ธํ๋ ค๋ฉด **๋ฅํฐ(Doctor)**๋ฅผ ์ํํ์ธ์:
python3 ~/.local/share/sari/doctor.py
๐งน ๋์๊ด ๋์ฒญ์ ๋ฐ ๋ณด์ (Caution!)
- ์ฅ๋ถ์ ์๋ฉธ: ์ญ์ ์ ๊ณต๋ค์ฌ ๋ง๋ ๊ธฐ๋ก(DB)๋ ํจ๊ป ๊ฐ๋ฃจ๊ฐ ๋ฉ๋๋ค โ ์ฌ์ค์น ํ ์ฌ์ธ๋ฑ์ฑ์ด๋ผ๋ ์ ์ค๊ธ ๋ ธ๊ฐ๋ค๊ฐ ํ์ํฉ๋๋ค.
- ์ํ์ ์๊ฐ: ์ฒซ ์คํ ์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆด ์ ์์ต๋๋ค. (ํธ๋ผ๋๋ฆผ ๋์๊ด 20,000ํ์ ํผ์ ๋น์งํ์ ๋ค๊ณ ์๊ฐํด๋ณด์๊ฒ๋, ์ง๊ทนํ ์ ์์ด๋ผ๋ค.)
๐ ์ฒ์์ ๋ณด์/ํ๋ผ์ด๋ฒ์
- ๋ชจ๋ ๊ณต๋ถ์ ๊ฒ์์ **์ฌ๋ฌ๋ถ์ ์๋ฐฉ(๋ก์ปฌ)**์์๋ง ์ํ๋ฉ๋๋ค.
- ์ฝ๋๊ฐ ์ง์ฅ(์ธ๋ถ ์๋ฒ)์ผ๋ก ์ ์ก๋๋ ๋ถ์์ฌ๋ ๊ฒฐ์ฝ ์ผ์ด๋์ง ์์ต๋๋ค.
- ๋ก๊ทธ์ ์บ์๋ ์ค์ง ์ฌ๋ฌ๋ถ์ ํ๋๋์คํฌ ๊น์ํ ๊ณณ์๋ง ๋ด์ธ๋ฉ๋๋ค. (๋์๋ธ๋ก๋ ๋ชป ํ์ณ๊ฐ๋ค.)
๐งผ Redaction (๋ฏผ๊ฐ์ ๋ณด ๋ง์คํน)
- ์ธ๋ฑ์ฑ/ํ ๋ ๋ฉํธ๋ฆฌ ๋ก๊ทธ ๊ธฐ๋ก ์ ๋ฏผ๊ฐ์ ๋ณด๋ฅผ ๋ง์คํนํฉ๋๋ค.
- ๊ธฐ๋ณธ๊ฐ์
redact_enabled=true์ด๋ฉฐ, ์ค์ ์์ ๋นํ์ฑํํ ์ ์์ต๋๋ค. - ๋ง์คํน ๋ฒ์/ํจํด์
app/indexer.py์_redact๋ก์ง ๊ธฐ์ค์ ๋๋ค.
๐งญ ๋ค์ค ์ํฌ์คํ์ด์ค๋ฅผ ๋๋ํ๊ฒ ์ฐ๋ ๋ฐฉ๋ฒ
โA๋ ๋ณด๊ณ ์ถ๊ณ B๋ ๋ณด๊ณ ์ถ์ด!โ ํ์๋ ๋ถ๋ค์ ์ํ ํ์ค์ ์ธ ์ถ์ฒ ํจํด์ด์์.
-
๋ฐฉ๋ฒ 1: ์ํฌ์คํ์ด์ค๋ณ๋ก ์ค์ ์ ๋๋ ๋๊ธฐ (๊ถ์ฅ)
A, B ๊ฐ๊ฐ์.codex/config.toml์ ๋ง๋ค์ด ๋๊ณ , ํ์ํ ๋ ๊ทธ ํด๋์์ ์คํํ์ธ์.
์ฌ๋ฆฌ ์ ์๋์ ํ์ฌ ์์น ๊ธฐ์ค์ผ๋ก ์์ง์ด๋ ์ฑ๊ฒฉ์ด๋ผ, ๊ทธ๊ฒ ์ ์ผ ๋ช ํํฉ๋๋ค. -
๋ฐฉ๋ฒ 2: ํ๋์ ์ํฌ์คํ์ด์ค๋ง ์ง์ค ๊ด๋ฆฌ
โ์ง๊ธ์ A๋ง ๋ด์ผ ํด!โ๋ผ๋ฉด B๋ ๊ณผ๊ฐํ๊ฒ ์์ผ์ธ์.
์ฌ๋ฆฌ๋ ํ ๋ฒ์ ํ๋์ ์ง์คํ๋ ์ ์๋์ด์์. (๋ฉํฐํ์คํน์ ๋ค์ ํ๊ธฐ์โฆ)
๐งฏ ๋ฌธ์ ํด๊ฒฐ (Troubleshooting)
Q. MCP ์ฐ๊ฒฐ์ด ์ ๋ผ์
command๊ฐbash์ธ์ง, ๊ทธ๋ฆฌ๊ณ ๋คํธ์ํฌ๊ฐ ํ์ฉ๋๋์ง ํ์ธํ์ธ์.- ์ ํ ํ๊ฒฝ์ด๋ผ๋ฉด ์ค์น๋ณธ bootstrap ๊ฒฝ๋ก๋ก ์ ํํ์ธ์.
- ๋ฐ๋ชฌ ์ํ ํ์ธ:
# macOS/Linux ~/.local/share/sari/bootstrap.sh daemon status # Windows %LOCALAPPDATA%\sari\bootstrap.bat daemon status
- ๊ธฐ๋์ด ๋๋ฆฌ๋ฉด
startup_timeout_sec๋ฅผ 120~180์ผ๋ก ์ฌ๋ ค๋ณด์ธ์.
Q. ์ฒซ ์คํ์ด ๋๋ฌด ๋๋ ค์
- ์ฒซ ์ธ๋ฑ์ฑ์ ์๋ ์๊ฐ์ด ์ข ๊ฑธ๋ฆฝ๋๋ค. (ํธ๋ผ๋๋ฆผ ๋์๊ด 20,000ํ์ ํผ์ ์ฒญ์ํ์ ๋ค๊ณ ์๊ฐํด๋ณด์ธ์.)
--workspace-root๋ก ๋ฒ์๋ฅผ ์ค์ด๋ฉด ํจ์ฌ ๋นจ๋ผ์ง๋๋ค. (์ ์๋๊ป ์ฒญ์ ๋ฒ์๋ฅผ ์ข๊ฒ ์๋ ค๋๋ฆฌ๋ ๋งค๋!)
Q. ํ ์คํธ๊ฐ ์ด์ ๋ฐ๋ชฌ๊ณผ ์ถฉ๋ํด์
- ๊ฒฉ๋ฆฌ๋ ํ๊ฒฝ์์ ์คํํ๋ ค๋ฉด
scripts/run_tests_isolated.sh๋ฅผ ์ฌ์ฉํ์ธ์. (HOME/registry/log/port ๋ถ๋ฆฌ)
Q. ์ ๋ฐ์ดํธ๊ฐ ์ ๋๋ ๊ฒ ๊ฐ์์
- ์ค์น๋ณธ
VERSION์ ํ์ธํ์ธ์:cat ~/.local/share/sari/VERSION - ํ์ํ๋ฉด ๊ฐ์ ์
๋ฐ์ดํธ:
curl -fsSL https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python3 - --update -y
Q. ์ค์ ํ์ผ์ด ์ฌ๊ธฐ์ ๊ธฐ ์๊ฒผ์ด์
- ์ฌ๋ฆฌ ์ ์๋์ ๊ธ๋ก๋ฒ ์ค์ ๊ณผ ํ๋ก์ ํธ ์ค์ ์ด ๋ค์์ฌ ํผ๋์ด ์ค๋ ๊ฑธ ๊ทน๋๋ก ํ์คํฉ๋๋ค.
๊ทธ๋์ ๊ธ๋ก๋ฒ~/.codex/config.toml์ ํํ๋กญ๊ฒ ์ ๋ฆฌํ๊ณ , **ํ๋ก์ ํธ๋ณ ์๋(์ค์ )**๋ง ์ฌ์ฉํ๋๋ก ์ ๋ํฉ๋๋ค.
์ค์ ์ ์ง์๊ฐ ๊ณง ์ฝ๋์ ํํ์ ๋๋ค.
๐งฉ ์ ์ค์ ์ ์๋์ผ๋ก ๋ค ์ ๊ณ ์ณ์ฃผ๋์?
Codex, Gemini, Claude, Cursorโฆ ์ด ๋
์๋ค์ ์ฑ๊ฒฉ๋ ๋ค๋ฅด๊ณ ์ฌ๋ ๊ณณ(์ค์ ๊ฒฝ๋ก)๋ ์ ๊ฐ๊ฐ์ด์์.
์ฌ๋ฆฌ ์ ์๋์ **โ๋จ์ ์ง ์๋ฐฉ ๊ฐ๊ตฌ ๋ฐฐ์น๋ฅผ ํจ๋ถ๋ก ๋ฐ๊พธ์ง ์๊ฒ ๋คโ**๋ ์๊ฒฉํ ๋๋์ ์ฒ ํ์ด ์์ต๋๋ค. ๐
(์ฌ์ค ์๋ชป ๊ฑด๋๋ฆฌ๋ฉด ์ง์ฅ๋ฌธ์ด ์ด๋ฆด ์ ์์ด์ ๊ทธ๋ ์ต๋๋ค.) ๋์ ์ฐธ๊ณ ํ ์ ์๋ **๋น๊ธ์(์ค์ ์์)**๋ ์๋์ ์ ์ด๋์์ผ๋ ์ง์ ์ฎ๊ฒจ ์ ์ด๋ณด์๊ฒ๋!
๐ฎ ์ฌ๋ฆฌ ์ ์๋ ๋ถ๋ ค๋จน๊ธฐ (Usage)
1๋จ๊ณ: ๋ด ํ๋ก์ ํธ ๊ณต๋ถ์ํค๊ธฐ
์ฌ๋ฌ๋ถ ๊ฐ๋ฐ ์ค๋ ฅ์ ๊ฒฐ์ ์ฒด(ํน์ ์ง์ฅ์์ ์จ ์คํ๊ฒํฐ ์ฝ๋)์ธ ํด๋๋ก ์ด๋ํด์ ์๋ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ์ธ์. ๊ทธ๋ผ ์ฌ๋ฆฌ ์ ์๋์ด ์งํก์ด๋ฅผ ์ง๊ณ ๊ทธ ํด๋๋ฅผ ์ ์ ์ด ๋ค์ง๊ธฐ ์์ํฉ๋๋ค!
# macOS/Linux
$HOME/.local/share/sari/bootstrap.sh init
# Windows
%LOCALAPPDATA%\sari\bootstrap.bat init
์ฐธ๊ณ :
--workspace-root๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์๋์ ์ด๋ ๋ฒ์๋ฅผ ์ ํํ ์ ์์ต๋๋ค.
์).../bootstrap.sh init --workspace-root /path/to/my_precious_code
2๋จ๊ณ: AI์๊ฒ ๋ฌผ์ด๋ณด๊ธฐ
์ด์ AI ์น๊ตฌ(Codex, Claude, Cursor ๋ฑ)๋ฅผ ์ด๊ณ ํ์์ฒ๋ผ ์ง๋ฌธํด๋ณด์ธ์.
"์ฌ๋ฆฌ ์ ์๋์ ์ฅ๋ถ๋ฅผ ๋ค์ ธ์ ๋ก๊ทธ์ธ ๋ก์ง์ด ์ด๋ ์ง์ฅ ๊ตฌ์์ ์๋์ง ์ฐพ์์ค."
"์ด ํ๋ก์ ํธ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์กฐ๋ฅผ ์ค๋ช ํด์ฃผ๊ฒ๋. ์ฌ์ ์ ์๋์ด ์๋ ๋๋ก ๋ง์ด์ผ."
๊ทธ๋ผ AI๊ฐ ์ฌ๋ฆฌ ์ ์๋์๊ฒ ๋ฌ๋ ค๊ฐ ์ฅ๋ถ๋ฅผ ํ์ธํ๊ณ , ์์ฃผ ์ ํํ ๋ต๋ณ์ ์ฌ๋ฌ๋ถ๊ป ์๋ ค์ค ๊ฑฐ์์! (๊ฐ๋ ๋ต๋ณ ๋์ "Stay awhile and listen"์ด๋ผ๊ณ ๋ถ์ฌ๋ ๋๋ผ์ง ๋ง์ธ์.) โจ
๐ Sari MCP vs Standard Tools (์ค์ธก ๊ธฐ๋ฐ ๋ถ์)
์๋ ์์น๋ **2026-02-02 ๊ธฐ์ค, ์ค์ ์ํฌ์คํ์ด์ค(636 files)**์์ ์ค์ธกํ ๋ฐ์ดํธ ํฌ๊ธฐ์
๋๋ค.
๋ถ์์ ์ฌ์ฉ๋ ์ ์ฅ์ ์ด๋ฆ/์ฝ๋ ๋ด์ฉ์ ๊ณต๊ฐํ์ง ์์์ต๋๋ค. (๊ตฌ์กฐยทํต๊ณ๋ง ๊ณต๊ฐ)
ํ ํฐ ์ถ์ ์ 1,000 bytes โ 280 tokens ๊ธฐ์ค์ผ๋ก ๊ณ์ฐํ์ต๋๋ค. (๋ชจ๋ธ๋ณ ์ค๋ฒํค๋๋ ์ ์ธ)
์ธก์ ๋ฐฉ๋ฒ ์์ฝ
- Sari MCP:
status(details),list_files,search_symbols์๋ต์ ๋ฐ์ดํธ ํฌ๊ธฐ ์ธก์ - Standard Tools:
ls -R,rg --files,rg "class.*Application"์ถ๋ ฅ์ ๋ฐ์ดํธ ํฌ๊ธฐ ์ธก์ - ๋์ผ ์ํฌ์คํ์ด์ค/๋์ผ ์์ /๋์ผ ํํฐ๋ก ๋น๊ต
1) ๊ตฌ์กฐ ํ์ (ํ์ผ ํธ๋ฆฌ ํ์ )
| ๋๊ตฌ | ์ธก์ ํญ๋ชฉ | ๋ฐ์ดํธ | ์ถ์ ํ ํฐ |
|---|---|---|---|
| Sari | status(details) |
1,649 | ~462 |
| Sari | list_files (limit=2000, returned=500) |
115,397 | ~32,311 |
| Standard | ls -R |
66,146 | ~18,521 |
| Standard | rg --files |
73,196 | ~20,495 |
ํด์:
status(details)๋ ๊ตฌ์กฐ ํ์ ์ฉ ์์ฝ์ผ๋ก ์ถ๋ ฅ๋์ด ๊ฐ์ฅ ์์ต๋๋ค.list_files๋ JSON ๋ฉํ๋ฐ์ดํฐ ๋๋ฌธ์ ์ ์ฒด ํธ์ถ ์ ์ถ๋ ฅ๋์ด ์ปค์ง ์ ์์ต๋๋ค.- ๋ฐ๋ผ์ ์์ฝ โ repo ์ขํ๊ธฐ โ ์์ธ ์์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ํ ํฐ ํจ์จ์ด ๋์ต๋๋ค.
2) ์ํธ๋ฆฌํฌ์ธํธ ์๋ณ (Application ํด๋์ค ํ์)
| ๋๊ตฌ | ์ธก์ ํญ๋ชฉ | ๋ฐ์ดํธ | ๊ฒฐ๊ณผ ์ |
|---|---|---|---|
| Sari | search_symbols Application |
1,008 | 4 |
| Standard | rg "class.*Application" |
667 | 4 |
ํด์:
- ์ถ๋ ฅ๋์ ์ ์ฌํ์ง๋ง, Sari๋ ์ฌ๋ณผ ํ์ /๊ฒฝ๋ก/๋ผ์ธ์ ๊ตฌ์กฐํํด ๋ฐํํฉ๋๋ค.
- ํ์ ๋จ๊ณ(
read_symbol)๋ก ์ด์ด์ง ๋ ์ถ๊ฐ ํ์ ๋น์ฉ์ด ์ค์ด๋ญ๋๋ค.
3) ๊ฒฐ๋ก (์ค์ธก ๊ธฐ๋ฐ)
Sari๋ โ์์ฝ โ ์ขํ๊ธฐ โ ์ฌ๋ณผ ์ฝ๊ธฐโ ์ํฌํ๋ก์ฐ์์ ๊ฐ์ฅ ํจ์จ์ ์
๋๋ค.
๋ฐ๋๋ก list_files๋ฅผ ์ ์ฒด์ ๋ฌด์ฌ์ฝ ํธ์ถํ๋ฉด ํ ํฐ ๋น์ฉ์ด ์ปค์ง ์ ์์ผ๋,
repo ์ง์ ๋๋ ์์ฝ ๋ชจ๋๋ฅผ ๋ฐ๋์ ์ฌ์ฉํ์ธ์.
โก ์ฑ๋ฅ๊ณผ ๋น์ฉ ์ต์ ํ ๊ฐ์ด๋
Sari๋ ์ธ๋ฑ์ฑ + FTS ๊ธฐ๋ฐ ๊ฒ์ ๊ตฌ์กฐ๋ผ์ **โ์ด๋ค ๋จ๊ณ์์ ์ฐ๋๋โ**์ ๋ฐ๋ผ ์ฒด๊ฐ ์ฑ๋ฅ์ด ํฌ๊ฒ ๋ฌ๋ผ์ง๋๋ค.
1) ๊ตฌ์กฐ ํ์ : ์์ฝ ๋ชจ๋๊ฐ ๊ธฐ๋ณธ
- ๊ถ์ฅ:
status(details)โrepo_candidatesโlist_files(repo=...) list_files๋ repo ๋ฏธ์ง์ ์ ์์ฝ ๋ชจ๋๋ก ๋์ํฉ๋๋ค.
ํฐ ์ํฌ์คํ์ด์ค์์ ์ ์ฒด ํ์ผ ๋ชฉ๋ก์ ํ ๋ฒ์ ๋คํํ๋ฉด ๋น์ฉ/ํ ํฐ ํญ์ฃผ๊ฐ ๋ฐ์ํฉ๋๋ค.- HTTP ์์ฒญ์ ์ค๋ ๋๋ณ read ์ ์ฉ ์ปค๋ฅ์ ์ ์ฌ์ฉํด ๋ณ๋ ฌ ์ฒ๋ฆฌ ํจ์จ์ ๋์ ๋๋ค.
2) ๊ฒ์ ์๋: FTS๊ฐ ์ผ์ ธ ์๋์ง ํ์ธ
status(details)์์fts_enabled: true์ธ์ง ๋จผ์ ํ์ธํ์ธ์.fts_enabled: false๋ฉด ๊ฒ์์ด LIKE ํด๋ฐฑ์ผ๋ก ์ ํ๋์ด ๋๋ ค์ง๊ณ ์ ํ๋๋ ๋จ์ด์ง๋๋ค.- FTS๊ฐ ์ผ์ ธ ์์ด๋ ์์ฃผ ์งง์ ์ฟผ๋ฆฌ(๊ธธ์ด < 3) ๋๋ ์ ๋์ฝ๋ ํฌํจ ์ฟผ๋ฆฌ๋ LIKE๋ก ํด๋ฐฑ๋ ์ ์์ต๋๋ค.
- ํ์ผ ์๊ฐ ๋ง๊ณ ๊ฒ์์ด ๋๋ฆฌ๋ค๋ฉด
status(details)์ ์์ง ์ถ์ฒ ๊ฒฝ๊ณ ๊ฐ ํ์๋ฉ๋๋ค.- ๊ธฐ๋ณธ ๊ธฐ์ค: 10,000 files ์ด์์ด๋ฉด embedded(Tantivy) ๊ถ์ฅ
- ์๊ณ๊ฐ:
DECKARD_ENGINE_SUGGEST_FILES
- FTS๋ ์์ถ ํด์ ๋ณ๋ชฉ์ ํผํ๊ธฐ ์ํด ๋ณ๋์
fts_content์ปฌ๋ผ์ ์ฌ์ฉํฉ๋๋ค. (๊ฒ์ CPU ๋ถ๋ด ๊ฐ์)
3) ์ํธ๋ฆฌํฌ์ธํธ ํ์์ ์ฌ๋ณผ ๊ธฐ๋ฐ์ด ์ ๋ฆฌ
search_symbolsโread_symbol์กฐํฉ์ ํ์ํ ์ฝ๋ ๋ธ๋ก๋ง ์ฝ์ด ํ ํฐ ๋น์ฉ์ ์ค์ ๋๋ค.read_file์ โ์ ๋ง ์ ์ฒด ํ์ผ์ด ํ์ํ ๋๋งโ ์ฌ์ฉํ์ธ์.- ๊ตฌ์กฐ์ ๋ญํน(Structural Boosting)์ด ์ ์ฉ๋์ด class/function/method ์ฌ๋ณผ์ ๋ ๋์ ์ ์๋ฅผ ๋ฐ์ต๋๋ค.
search๋ ์ ํํ ์ฌ๋ณผ ์ด๋ฆ ๋งค์นญ์ ์ถ๊ฐ ๊ฐ์ค์น๋ฅผ ๋ถ์ฌํฉ๋๋ค.
4) ํฐ ๋ ํฌ์ผ์๋ก ํํฐ๋ง์ด ํต์ฌ
repo,file_types,path_pattern์ ์ ๊ทน ์ฌ์ฉํ์ธ์.- ์)
list_files { repo: "sari", file_types: ["py"] }
5) ๋๋ ๋ธ๋์น ๋ณ๊ฒฝ(Git checkout) ๋์
.git์ด๋ฒคํธ ๊ฐ์ง ์ ๊ฐ๋ณ ํ์ผ ์ด๋ฒคํธ ๋์ rescan์ผ๋ก ํฉ์ณ ์ฒ๋ฆฌํฉ๋๋ค.- debounce๋
DECKARD_GIT_CHECKOUT_DEBOUNCE(๊ธฐ๋ณธ 3์ด)
6) ๋๋ ์ด๋ฒคํธ ์ฑ๋ฅ/๋ณต๊ตฌ
- ์ธ๋ฑ์ฑ ์ฝ์ผ๋ ์ค๋ Sharded Lock์ผ๋ก ๋ถ์ฐ๋์ด ๋๊ท๋ชจ ์ด๋ฒคํธ์์ ๋ณ๋ชฉ์ ์ค์
๋๋ค.
- ์ค๋ ์:
DECKARD_COALESCE_SHARDS(๊ธฐ๋ณธ 16)
- ์ค๋ ์:
- ์คํจํ ์ธ๋ฑ์ฑ ์์
์ DLQ(Dead Letter Queue) ๋ก ์ ์ฅ๋ฉ๋๋ค.
- ์ฌ์๋ ๊ฐ๊ฒฉ: 1๋ถ โ 5๋ถ โ 1์๊ฐ
doctor์์ 3ํ ์ด์ ์คํจํ ํญ๋ชฉ์ ๊ฒฝ๊ณ ๋ก ํ์ํฉ๋๋ค.
๐ ๏ธ ๋ด๊ฐ ์ฐ๋ ์ฑ์ ์ฐ๊ฒฐํ๊ธฐ (์์ธ ๊ฐ์ด๋)
๐ค Claude Desktop ์ฑ ์ฐ๋
์ค์ ํ์ผ(claude_desktop_config.json)์ ์ฐพ์์ ์๋ ๋ด์ฉ์ ์ ๋ฃ์ด์ฃผ์ธ์.
์ด๊ฑด ๋ง์น ์ ์๋ ์ด๋ฆํ๋ฅผ ๋ฌ์์ฃผ๋ ์์
์
๋๋ค.
{
"mcpServers": {
"sari": {
"command": "bash",
"args": [
"-lc",
"curl -fsSL https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python3 - -y; exec ~/.local/share/sari/bootstrap.sh --transport stdio"
],
"env": {
"DECKARD_WORKSPACE_ROOT": "/Users/[์ฌ์ฉ์๋ช
]/path/to/workspace",
"DECKARD_RESPONSE_COMPACT": "1"
}
}
}
}
๐งฉ Codex / Gemini ์ค์ ์์ (config.toml)
[mcp_servers.sari]
command = "bash"
args = ["-lc", "curl -fsSL https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python3 - -y; exec ~/.local/share/sari/bootstrap.sh --transport stdio"]
env = { DECKARD_WORKSPACE_ROOT = "/Users/[์ฌ์ฉ์๋ช
]/path/to/workspace", DECKARD_RESPONSE_COMPACT = "1" }
startup_timeout_sec = 60
ํ๋๋ณ ์์ธ ์ค๋ช
command: ์ฌ๋ฆฌ๋ฅผ ์คํํ ๊ฒฝ๋ก์ ๋๋ค.command: ๊ธฐ๋ณธ์bash(๋คํธ์ํฌ ์๋ ์ค์น ๋ฐฉ์).args:curl | python3๋ก ์ค์น ํbootstrap.sh์คํ.env: ํ๊ฒฝ ๋ณ์๋ฅผ ๊ฐ์ ๋ก ์ฃผ์ ํฉ๋๋ค.DECKARD_WORKSPACE_ROOT๋ workspace-root๋ฅผ ๊ณ ์ ํ๋ ค๊ณ ๋ฃ์ต๋๋ค.
startup_timeout_sec: ๋ฐ๋ชฌ ๊ธฐ๋ ๋๊ธฐ ์๊ฐ(์ด).
์ด๊ธฐ ์ธ๋ฑ์ฑ์ด ๊ธธ๋ค๋ฉด 120~180์ผ๋ก ๋๋ ค๋ณด์ธ์.
์ค์ ๊ฒฝ๋ก ์ฐ์ ์์(์์ฝ)
DECKARD_CONFIG/LOCAL_SEARCH_CONFIG<workspace>/.codex/tools/sari/config/config.json- ํจํค์ง ๊ธฐ๋ณธ config
๐ ํ ๋ ๋ฉํธ๋ฆฌ ๋ก๊ทธ
tool=search/tool=list_files๋ฑ ๋๊ตฌ ์คํ ๋ก๊ทธ๊ฐ ๊ธฐ๋ก๋ฉ๋๋ค.search-first์ ์ฑ ์๋ฐ/๊ฒฝ๊ณ ๋ ๋ณ๋ ๋ก๊ทธ ํญ๋ชฉ์ผ๋ก ๋จ์ต๋๋ค.
๐งต ์๋ต ์์ถ ๋ชจ๋
DECKARD_RESPONSE_COMPACT=1์ด๋ฉด MCP ์๋ต JSON์ด minified๋ก ์ถ๋ ฅ๋ฉ๋๋ค. (๊ธฐ๋ณธ๊ฐ)DECKARD_RESPONSE_COMPACT=0์ด๋ฉด ๊ธฐ์กด pretty JSON ์ถ๋ ฅ์ผ๋ก ๋ณต์๋ฉ๋๋ค.list_files๋ compact ๋ชจ๋์์paths๋ง ๋ฐํํฉ๋๋ค. (verbose ๋ชจ๋์์๋งfiles/meta)
์ฌ๋ฌ ์ํฌ์คํ์ด์ค๋ฅผ ๋ฃ์ ์ ์๋์?
- ํ์ฌ๋
--workspace-root๋จ์ผ ๊ฒฝ๋ก๋ง ์ง์ํฉ๋๋ค. - ์ฌ๋ฌ ์ํฌ์คํ์ด์ค๋ฅผ ์ฐ๋ ค๋ฉด ๊ฐ ์ํฌ์คํ์ด์ค๋ง๋ค ๋ณ๋ ์ค์ ์ ๊ถ์ฅํฉ๋๋ค.
env ์์ด๋ ๋๋์?
- ๋ฉ๋๋ค.
args์--workspace-root๊ฐ ์์ผ๋ฉด ์ ์ ๋์ํฉ๋๋ค. - ๋ค๋ง ํ๊ฒฝ ๋ณ์๊ฐ ์ฐ์ ๋๋๋ก ์ฌ์ฉ ํ๊ฒฝ์ด ๊ตฌ์ฑ๋ ๊ฒฝ์ฐ๊ฐ ์์ด, ํผ์ ์ ์ค์ด๋ ค๋ฉด
args์env๋ฅผ ๊ฐ์ด ๋ง์ถฐ๋๋ ๊ฒ์ด ์์ ํฉ๋๋ค.
args์ env๊ฐ ์๋ก ๋ค๋ฅด๋ฉด?
DECKARD_WORKSPACE_ROOT(ํ๊ฒฝ ๋ณ์)๊ฐ ์์ ๊ถ์๋ฅผ ๊ฐ์ง๋๋ค.
ํ์ง๋ง ๋ ๊ฐ์ด ๋ค๋ฅด๋ฉด ์ ์๋์ด "์ด๋๋ก ๊ฐ๋ผ๋ ๊ฑด๊ฐ!" ํ๊ณ ์งํก์ด๋ฅผ ํ๋๋ฅด์ค ํ ๋, ํญ์ ๋์ผํ๊ฒ ๋ง์ถ๋ ๊ฑธ ์ถ์ฒํ๋ค.
๐ก Cursor/CLI์์ ์ต์ ๋ฃ๋ ๋ฐฉ๋ฒ
Cursor/Claude/Gemini/Codex ๊ฐ์ MCP ํด๋ผ์ด์ธํธ๋ env ๋ธ๋ก์ผ๋ก ์ต์
์ฃผ์
์ด ๊ฐ๋ฅํฉ๋๋ค.
CLI๋ง ์ฐ๋ ๊ฒฝ์ฐ์ ๋ค์ ์ค ํ๋๋ฅผ ์ฌ์ฉํ์ธ์.
A) ์์์ ์ง์ env ์ง์
DECKARD_ENGINE_TOKENIZER=cjk DECKARD_ENGINE_AUTO_INSTALL=1 \
~/.local/share/sari/bootstrap.sh --transport stdio
B) ๋ํผ ์คํฌ๋ฆฝํธ
#!/usr/bin/env bash
export DECKARD_ENGINE_TOKENIZER=cjk
export DECKARD_ENGINE_AUTO_INSTALL=1
exec ~/.local/share/sari/bootstrap.sh --transport stdio
--workspace-root๋ฅผ ์๋ตํ๋ฉด ์ด๋ค ์ฌ์์ด?
- ์คํ ์์น๋ฅผ ๊ธฐ์ค์ผ๋ก ์ํฌ์คํ์ด์ค๋ฅผ ๋ฉ๋๋ก ์ถ์ ํฉ๋๋ค.
- ํ์ฌ ํด๋ ๋๋ ์์ ํด๋์
.codex-root๊ฐ ์์ผ๋ฉด "์ฐพ์๋ค!" ํ๊ณ ์ฌ์ฉ - ์๋ค๋ฉด ํ์ฌ ํด๋ ์ ์ฒด๋ฅผ ์๊ธฐ ์๋ฐฉ์ธ ์ค ์๋๋ค.
- ํ์ฌ ํด๋ ๋๋ ์์ ํด๋์
์: ํ ๋๋ ํ ๋ฆฌ์์ ์ค์๋ก ์คํํ๋ฉด?
- ์๋์น ์๊ฒ ์ฌ๋ฌ๋ถ์ '๋น๋ฐ ์ฌ์ง์ฒฉ'๊ณผ '๋ค์ด๋ก๋ ํด๋' ์ ์ฒด๊ฐ ํธ๋ผ๋๋ฆผ ์ฅ๋ถ์ ๊ธฐ๋ก๋ ์ ์์ต๋๋ค.
์ ์ ๊ฑด๊ฐ์ ์ํด--workspace-root๋ฅผ ๋ช ์ํ๋ ๊ฒ์ ๊ฐ๋ ฅํ๊ณ ๊ฐ์ ํ๊ฒ ์ถ์ฒํ๋ค.
์ค์ ํ์ผ์ด ๋ ๊ตฐ๋ฐ ์์ผ๋ฉด ์ด๋ป๊ฒ ๋๋์?
- ์ฌ๋ฆฌ ์ ์๋์ **ํ๋ก์ ํธ ์ค์ (ํ์ฅ ์ค์ฌ)**์ ๊ฐ์ฅ ์ ๋ขฐํฉ๋๋ค.
๊ธ๋ก๋ฒ ์ค์ ๊ณผ ํจ๊ป ์กด์ฌํ๋ฉด ์ ์๋์ด ํท๊ฐ๋ คํ์๋,
install.py๋ ์๋น๋กญ๊ฒ ๊ธ๋ก๋ฒ์sari๋ธ๋ก์ ์ ๊ฑฐํด ๋ฒ๋ฆฐ๋ค๋ค. (์ค์ง ์ง์!)
โจ๏ธ Cursor (AI ์๋ํฐ) ์ฐ๋
- ํ๊ฒฝ์ค์ (Settings) > MCP ๋ฉ๋ด๋ฅผ ํด๋ฆญํ์ธ์.
- + Add New MCP Server ๋ฒํผ์ ๋๋ฆ ๋๋ค.
- ์ด๋ฆ์
sari, ํ์ ์stdio๋ฅผ ์ ํํ์ธ์. - Command ์นธ์
/Users/[์ฌ์ฉ์๋ช ]/.local/share/sari/bootstrap.sh๋ฅผ ์ ๋ ฅํ๊ณ 'Save' ํ๋ฉด ๋!
๐๏ธ ๋์๊ด ํ์ (์ญ์ ๋ฐฉ๋ฒ - Uninstall)
์ด์ ์ฑ์ญ์ ํํ๊ฐ ์ฐพ์์๊ฑฐ๋, ์ ์๋์ ์์๋ฆฌ๊ฐ ๋ฃ๊ธฐ ์ซ๋ค๋ฉด ์ธ์ ๋ ๋ณด๋ด๋๋ฆด ์ ์์ต๋๋ค. ํฐ๋ฏธ๋์ ์๋ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ์ธ์. (๋๋ฌผ ์ฃผ์)
# ๋ง๋ฒ ์ฃผ๋ฌธ์ --uninstall ์ต์
์ ๋ถ์ด๋ฉด ์ ์๋์ด ์ง์ ์ธ์ ๋ ๋์ญ๋๋ค.
curl -fsSL https://raw.githubusercontent.com/BaeCheolHan/sari/main/install.py | python3 - --uninstall
๋๋ ์ค์น๋ณธ ๊ธฐ์ค์ผ๋ก ์ด๋ ๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค:
# macOS/Linux
~/.local/share/sari/bootstrap.sh uninstall
# Windows
%LOCALAPPDATA%\sari\bootstrap.bat uninstall
์ญ์ ํ๋ฉด ๋ฌด์์ด ์ ํ๋๋์? (์ด๋ณ์ ๋ฏธํ)
- ๊ฑฐ์ฒ ์ ํ: ์ฌ๋ฆฌ ์ ์๋์ด ๋จธ๋ฌผ๋ ๋์๊ด๊ณผ ๋ก์ ์ฅ๋ถ(index.db)๋ฅผ ํธ๋ฆฌ์คํธ๋ผ์ ๋ถ๊ธธ๋ก ์๋ฉธ์ํต๋๋ค.
- ์๋ฅ์ด ์ ๋ น ํด์น:
install.py --uninstall์ Codex์ Gemini ์์ชฝ์ ์ธ์ฅ์ ๋ชจ๋ ์ง์๋ฒ๋ฆฌ๋ ๊ฐ๋ ฅํ ์ ํ ์์์ ๊ฑฐํํฉ๋๋ค. - ์ ํ์ ์๋ณ:
bootstrap.sh uninstall์ ์ค์ง Codex์ ์ธ์ฅ๋ง ์ง์ฐ๊ณ ๋ ๋๋ ์ ์ ๋ ์ด๋ณ์ ์ ์ฌํฉ๋๋ค. (Gemini/Claude ๋ฑ์ ๊ทธ๋๋ก ๋จ์ต๋๋ค.) - ์๋์ฐ ์ฃผ์:
bootstrap.bat uninstall์ ์ค์ ํ์ผ์ ์ ๋ฆฌํ์ง ์์ต๋๋ค. ํ์ํ๋ฉด ์๋์ผ๋กconfig.toml์์sari๋ธ๋ก์ ์ ๊ฑฐํ์ธ์. - ๊น๋ํ ์น์ฒ: ์ฌ๋ฌ๋ถ์ ์ปดํจํฐ์ ๊ทธ ์ด๋ค ์ง์ฅ์ ์ฐ๊บผ๊ธฐ๋ ๋จ๊ธฐ์ง ์๊ณ ๊ณ ๊ฒฐํ๊ฒ ์ฌ๋ผ์ง์ญ๋๋ค!
๐ค MCP ์๋ต ํฌ๋งท (PACK1) ๊ฐ์ด๋
์ฌ๋ฆฌ v2.5.0๋ถํฐ๋ ํ ํฐ ์ ์ฝ์ ์ํด PACK1์ด๋ผ๋ ์์ถ ํ ์คํธ ํฌ๋งท์ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํฉ๋๋ค. JSON์ ๋ถํ์ํ ๊ดํธ์ ๊ณต๋ฐฑ์ ์ ๊ฑฐํ์ฌ ์ฝ 30~50%์ ํ ํฐ์ ์ ์ฝํฉ๋๋ค.
1. ํฌ๋งท ๊ฐ์
- ํค๋(Header):
PACK1 <tool> key=value ... - ๋ ์ฝ๋(Record):
<type>:<payload>(ํ ์ค์ ํ๋์ฉ) - ์ธ์ฝ๋ฉ: ํน์๋ฌธ์๋ ๊ณต๋ฐฑ์ด ํฌํจ๋ ๊ฐ์ ์์ ํ๊ฒ URL ์ธ์ฝ๋ฉ๋ฉ๋๋ค.
ENC_ID: ์๋ณ์์ฉ (๊ฒฝ๋ก, ์ด๋ฆ ๋ฑ).safe="/._-:@"ENC_TEXT: ์ผ๋ฐ ํ ์คํธ์ฉ (์ค๋ํซ, ๋ฉ์์ง ๋ฑ).safe=""
2. ์ฃผ์ ๋๊ตฌ ์์
list_files
PACK1 list_files offset=0 limit=100 returned=2 total=2 total_mode=exact
p:src/main.py
p:src/utils.py
search_symbols
PACK1 search_symbols q=User limit=50 returned=1 total_mode=none
h:repo=my-repo path=src/user.py line=10 kind=class name=User
status
PACK1 status returned=5
m:index_ready=true
m:scanned_files=100
m:indexed_files=100
m:errors=0
m:fts_enabled=true
3. ์๋ฌ ์ฝ๋ (Error Codes)
์ค๋ฅ ๋ฐ์ ์ PACK1 <tool> ok=false ํค๋์ ํจ๊ป ์๋ ์ฝ๋๊ฐ ๋ฐํ๋ฉ๋๋ค.
| ์ฝ๋ | ์ค๋ช |
|---|---|
INVALID_ARGS |
์๋ชป๋ ์ธ์ ์ ๋ฌ |
NOT_INDEXED |
์ธ๋ฑ์ฑ์ด ์๋ฃ๋์ง ์์ |
REPO_NOT_FOUND |
์กด์ฌํ์ง ์๋ ์ ์ฅ์ |
IO_ERROR |
ํ์ผ ์ฝ๊ธฐ/์ฐ๊ธฐ ์คํจ |
DB_ERROR |
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๋ฅ |
INTERNAL |
๋ด๋ถ ์๋ฒ ์ค๋ฅ |
์ฐธ๊ณ : ๊ธฐ์กด JSON ํฌ๋งท์ด ํ์ํ๋ค๋ฉด ํ๊ฒฝ๋ณ์
DECKARD_FORMAT=json์ ์ค์ ํ์ธ์. (๋๋ฒ๊น ์ฉ) ์๋ฌ์๋hint๊ฐ ํจ๊ป ํฌํจ๋ ์ ์์ต๋๋ค. (์:run scan_once,run sari doctor)
๐ฉบ MCP status/doctor ๊ฒฝ๊ณ ์๋ด
์๋ ์ํ๋ MCP status/doctor์์ ๊ฒฝ๊ณ ๋ก ๋
ธ์ถ๋ฉ๋๋ค.
1) tokenizer ๋ฑ๋ก ์คํจ
engine tokenizers not registered; using default tokenizer
2) ํ๋ซํผ์ฉ ๋ฒ๋ค ๋๋ฝ
tokenizer bundle not found for <platform_tag>
ํด๊ฒฐ:
app/engine_tokenizer_data/์ ํด๋น OS์ฉ wheel ํฌํจ- ํ์ ์
scripts/prune_tokenizer_bundles.sh๋ก ์ ๋ฆฌ
๐๏ธ ๊ฐ๋ฐ์๋ฅผ ์ํ ์ ์ (Tech Specs)
- ์ธ์ด: Python 3.9+ (ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ์ฌ์ฉํ๋ ์ ๋ก ๋ํ๋์!)
- DB: SQLite (WAL ๋ชจ๋) + FTS5 (์ ๋ฌธ ๊ฒ์ ๊ธฐ์ )
- ํต์ : MCP (Model Context Protocol)
- ๊ตฌ์กฐ:
- Daemon: ์ค์ ๋ก ๊ณต๋ถํ๊ณ ๊ฒ์์ ์ฒ๋ฆฌํ๋ ํต์ฌ ๋ณธ์ฒด
- Proxy: AI ์ฑ๊ณผ Daemon ์ฌ์ด์ ๋น ๋ฅธ ๋ฉ์ ์
๐ง ์ง์ ๋๊ตฌ (Call Graph / Snippet / Context / Dry-run Diff)
1) Call Graph (ํธ์ถ ๊ด๊ณ)
MCP tool: call_graph
CLI:
sari call-graph --symbol process_file --depth 2
# ์ฌ๋ณผ์ด ๊ฒน์น ๋๋ symbol_id๋ก ์ ํํ ์ง์
sari call-graph --symbol-id "<sid>" --depth 2
# ํธ๋ฆฌ ์ถ๋ ฅ
sari call-graph --symbol process_file --depth 2 --format tree
# ๊ฒฝ๋ก ํํฐ
sari call-graph --symbol process_file --include-path sari/core --exclude-path tests
# ์ ๋ ฌ ๊ธฐ์ค
sari call-graph --symbol process_file --format tree --sort name
์ค๋ช :
search_symbols๊ฒฐ๊ณผ์qualname/symbol_id๊ฐ ํฌํจ๋ฉ๋๋ค.symbol_id๋ฅผ ์ ๋ฌํ๋ฉด ํธ์ถ ๊ด๊ณ๊ฐ ํจ์ฌ ์ ํํ๊ฒ ๋งคํ๋ฉ๋๋ค.DECKARD_CALLGRAPH_PLUGIN์ผ๋ก ์ ์ ๋ถ์ ํ๋ฌ๊ทธ์ธ์ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค.- ์ฌ๋ฌ ๊ฐ๋ ์ผํ๋ก ์ฐ๊ฒฐ:
mod1,mod2 augment_neighbors(direction, neighbors, context)๋๋filter_neighbors(...)๊ตฌํ ๊ฐ๋ฅ.- ์๋ฌ ๋ก๊ทธ:
DECKARD_CALLGRAPH_PLUGIN_LOG=/tmp/callgraph.log
- ์ฌ๋ฌ ๊ฐ๋ ์ผํ๋ก ์ฐ๊ฒฐ:
- ์ ํ๋ ํํธ๊ฐ
precision_hint๋ก ์ ๊ณต๋ฉ๋๋ค (์ธ์ด๋ณ ์ธ๋ถํ). search_symbols๊ฒฐ๊ณผ์๋precision_hint๊ฐ ํฌํจ๋ฉ๋๋ค.- ํ๋ฌ๊ทธ์ธ ๋งค๋ํ์คํธ:
DECKARD_CALLGRAPH_PLUGIN_MANIFEST=/path/to/manifest.json - ๋งค๋ํ์คํธ ์คํค๋ง:
- JSON ๋ฆฌ์คํธ:
["mod1", "mod2"] - ๋๋ ๊ฐ์ฒด:
{"plugins": ["mod1", "mod2"]}
- JSON ๋ฆฌ์คํธ:
- strict ๊ฒ์ฆ:
DECKARD_CALLGRAPH_PLUGIN_MANIFEST_STRICT=1 call_graph_health์์ API ๋ถ์ผ์น/๋ก๋ ์คํจ ์์ธ ํ์ธ ๊ฐ๋ฅquality_score(0-100)๋ก ์ ์ ํด์ ์ ๋ขฐ๋ ์ ๊ณต (ํ์ผ ํฌ๊ธฐ/๊ด๊ณ ๋ฐ๋ ๋ฐ์)
- ํ๋ฌ๊ทธ์ธ ๋งค๋ํ์คํธ:
์ธ์ด๋ณ ํน์ด์ฌํญ:
- Python: AST ๊ธฐ๋ฐ, ์ ํ๋ ๋์. ๋์ ํธ์ถ/๋ฆฌํ๋ ์ ์ ํ๊ณ.
- JS/TS/Java/Kotlin/Go/C/C++: ์ ๊ท์ ๊ธฐ๋ฐ ํ์๋ก ํธ์ถ ๊ด๊ณ ์ ๋ฐ๋ ๋ฎ์.
- ์ค๋ฒ๋ก๋/์ธํฐํ์ด์ค/๋ฆฌํ๋ ์ /๋์ ๋์คํจ์น์ ์ฝํจ.
- ๋์ผ ์ด๋ฆ ์ฌ๋ณผ ์ถฉ๋ ๊ฐ๋ฅ โ
symbol_id๊ถ์ฅ.
2) Save / Get Snippet
MCP tools: save_snippet, get_snippet
CLI:
sari save-snippet --path "core/db.py:100-150" --tag "db-connection-pattern"
sari get-snippet --tag "db-connection-pattern"
sari get-snippet --tag "db-connection-pattern" --history
sari get-snippet --tag "db-connection-pattern" --no-remap
sari get-snippet --tag "db-connection-pattern" --update
sari get-snippet --tag "db-connection-pattern" --update --diff-path /tmp/snippet.diff
์ค๋ช :
- ์ ์ฅ ์ ์ค๋ํซ ์ฃผ๋ณ ์ต์ปค(์/๋ค ๋ผ์ธ)๋ฅผ ํจ๊ป ๊ธฐ๋กํฉ๋๋ค.
- ํ์ผ์ด ๋ฐ๋์ด๋
get_snippet์ ์ต์ปค/๋ด์ฉ ๋งค์นญ์ผ๋ก ์๋ ์ฌ๋งคํ(remap)ํฉ๋๋ค. - ์ค๋ํซ ๋ด์ฉ์ด ๋ฐ๋๋ฉด ์ด์ ๋ฒ์ ์ด
snippet_versions์ ์๋ ๋ณด๊ด๋ฉ๋๋ค. --update๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฆฌ๋งคํ๋ ์์น/๋ด์ฉ์ DB์ ๋ฐ์ํฉ๋๋ค.- ๋ฆฌ๋งคํ ๊ฒฐ๊ณผ์๋
diff(๋ณ๊ฒฝ ์์ฝ)๊ฐ ํฌํจ๋ฉ๋๋ค. --diff-path๋ฅผ ์ง์ ํ๋ฉด diff๋ฅผ ํ์ผ๋ก ์ ์ฅํฉ๋๋ค.--diff-path๊ฐ ๋น์ด ์์ผ๋ฉด ๊ธฐ๋ณธ ๊ฒฝ๋ก๋~/.cache/sari/snippet-diffs/<tag>.diff์ ๋๋ค.--update์ ์ ์ฅ๋ ์ค๋ ์ท:<tag>_<id>_<ts>_stored.txt,<tag>_<id>_<ts>_current.txt- ๋ฆฌ๋งคํ์ด ์ ํจํ์ง ์์ผ๋ฉด ์
๋ฐ์ดํธ๊ฐ ์คํต๋ฉ๋๋ค (
update_skipped_reason).
3) Archive / Get Context
MCP tools: archive_context, get_context
CLI:
sari archive-context --topic "PricingLogic" --content "์ฟ ํฐ ์ ์ฉ ์ ํ ์ธ ๊ณ์ฐ" --related-files core/pricing.py api/payment.py
sari archive-context --topic "PricingLogic" --content "..." --source "issue-102" --valid-from 2024-02-01
sari get-context --topic "PricingLogic"
sari get-context --query "Pricing" --as-of 2024-06-01
์ค๋ช :
source,valid_from,valid_until,deprecated๋ฅผ ๊ธฐ๋กํ ์ ์์ต๋๋ค.get_context --as-of๋ ์์ ๊ธฐ์ค์ผ๋ก ์ ํจํ ์ปจํ ์คํธ๋ง ๋ฐํํฉ๋๋ค.
4) Dry-run Diff
MCP tool: dry_run_diff
CLI:
sari dry-run-diff --path core/db.py --content "$(cat /tmp/new_db.py)"
sari dry-run-diff --path core/db.py --content "$(cat /tmp/new_db.py)" --lint
์ค๋ช :
- ๊ธฐ๋ณธ์ ๊ตฌ๋ฌธ ์ฒดํฌ๋ง ์ํํฉ๋๋ค.
--lint๋๋DECKARD_DRYRUN_LINT=1์ค์ ์, ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฆฐํฐ(ruff/eslint)๊ฐ ์์ผ๋ฉด ์คํํฉ๋๋ค.
๐งฐ Composite Tool (grep_and_read)
MCP tool: grep_and_read
์ค๋ช
:
- ๊ฒ์ ๊ฒฐ๊ณผ ์์ N๊ฐ ํ์ผ์ ์ฆ์ ์ฝ์ด์ต๋๋ค.
searchโread_file๋ฐ๋ณต์ ์ค์ด๊ธฐ ์ํ ํ ํฐ/ํด ์ ๊ฐ ๋๊ตฌ์ ๋๋ค.
์์:
{ "name": "grep_and_read", "arguments": { "query": "process_file", "limit": 5, "read_limit": 2 } }
๐ฉบ ์ง๋จ (Doctor)
CLI:
sari doctor
sari doctor --auto-fix
sari doctor --auto-fix --auto-fix-rescan
์ค๋ช :
--auto-fix๋ ๊ฐ๋ฅํ ํญ๋ชฉ์ ๋ํด ์๋ ๋ง์ด๊ทธ๋ ์ด์ ์ ์๋ํฉ๋๋ค.--auto-fix-rescan์ ์๋ ์์ ์ดํscan_once๋ฅผ ์คํํฉ๋๋ค.- ์งํ ์ํ๋
Auto Fix Rescan Start/Auto Fix Rescanํญ๋ชฉ์ผ๋ก ํ์๋ฉ๋๋ค. - ์๋ ์์ ์ด ์คํจํ๋ฉด
Auto Fix Rescan Skipped๋ก ํ์๋ฉ๋๋ค.
- ์งํ ์ํ๋
โ ์ฃ์ง ํ ์คํธ
scripts/run_edge_tests.sh
CI ํฌํจ:
scripts/run_tests_isolated.sh
๐ Call-Graph ํ๋ฌ๊ทธ์ธ ํฌ์ค ์ฒดํฌ
MCP tool: call_graph_health
๐ DB ๋จ์ผ Writer ์ ์ฑ (์ค์)
Sari๋ SQLite์ ๋จ์ผ writer ์์น์ ๊ฐ์ ํฉ๋๋ค.
- ์ฐ๊ธฐ ์์ ์ DBWriter ์ ์ฉ ์ค๋ ๋์์๋ง ์ํ๋ฉ๋๋ค.
- ๋ด๋ถ์์ ๋ณ๋ writer ์ปค๋ฅ์ ์ ์์ฑํ์ง ์์ต๋๋ค.
- ์ง์ DB ์ฐ๊ธฐ๋ฅผ ํธ์ถํ๋ฉด
DB write attempted outside single-writer thread์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์ฆ, DB ์ฐ๊ธฐ๋ ํญ์ ์ธ๋ฑ์ ํ์ดํ๋ผ์ธ์ ํตํด์๋ง ์ํ๋๋๋ก ์ค๊ณ๋์์ต๋๋ค.
์ธ๋ถ ํ์ฅ/์คํฌ๋ฆฝํธ์์ DB๋ฅผ ์ง์ ์ฐ๋ ๊ฒ์ ์ง์ํ์ง ์์ต๋๋ค.
๐ ๋ผ์ด์ ์ค (License)
์ด ํ๋ก์ ํธ๋ Apache License 2.0์ ๋ฐ๋ฅด๊ณ ์์ด์. ๋๊ตฌ๋ ์์ ๋กญ๊ฒ ์ฌ์ฉํ๊ณ , ๊ณ ์น๊ณ , ๊ณต์ ํ ์ ์์ต๋๋ค.
๋ฐฐํฌ ์ NOTICE ํ์ผ์ ๊ณ ์ง์ฌํญ๋ ํจ๊ป ํฌํจํด์ผ ํฉ๋๋ค.
"์, ์ด์ ์ฌ๋ฆฌ ์ ์๋๊ณผ ํจ๊ป ์ฌ๋ฌ๋ถ์ ์ฝ๋ ์์ ์จ๊ฒจ์ง ๋น๋ฐ์ ์ฐพ์๋ณด์๊ฒ ๋?" ๐งโโ๏ธโจ
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sari-0.1.1.tar.gz.
File metadata
- Download URL: sari-0.1.1.tar.gz
- Upload date:
- Size: 71.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e42e38dfb25bc9c25fb5eebba8e7a410b669820c1a1f2b4c6f46870495596cd
|
|
| MD5 |
402fcc46b5bc9e0a679165f05e87ca17
|
|
| BLAKE2b-256 |
9c9a9319912b509082f8c80e2c921fd15052b9efa3005962319d83e80e2028f6
|
File details
Details for the file sari-0.1.1-py3-none-any.whl.
File metadata
- Download URL: sari-0.1.1-py3-none-any.whl
- Upload date:
- Size: 71.7 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4e1772710b6d803adeb77ba00883df9152642da350d1d1c5289d8aa966f94e2
|
|
| MD5 |
b44dbf606494a45f8fa954607e807efc
|
|
| BLAKE2b-256 |
e9370de98fa04e6024468fcdc866e239c5eeffe5d1ce24a6c6499f46db5bb680
|