Skip to main content
Glama
notx2wice

graphiti-folder

by notx2wice
README.md
# Graphiti Folder

하나 이상의 Markdown·텍스트 폴더를 **삭제하지 않는 시간 지식 그래프**로 만든다.
새 문서는 새 기억으로, 수정된 문서는 새 revision으로 덧붙인다.

이 도구가 맡는 범위는 분명하다.

```text
내 문서 폴더들 → 변경 확인 → Graphiti에 제한된 수만 추가 → 검색과 출처 확인
```

- 원본 문서는 바꾸지 않는다.
- Graphiti DB에서 일상적인 삭제·초기화를 제공하지 않는다.
- AI가 만든 Fact를 원문보다 더 확실한 사실로 취급하지 않는다.
- 동기화는 반드시 `--limit N` 또는 `--all`을 명시해야 한다.

## 5분 시작

필요한 것은 macOS 또는 Linux, Python 3.12, [`uv`](https://docs.astral.sh/uv/),
Neo4j, OpenRouter API 키다. 로컬 Neo4j는 Docker로 실행할 수 있고 웹에서는 Neo4j
Aura 같은 관리형 서버를 연결할 수 있다. Graphiti는 Entity·Fact 추출과 검색 벡터
생성에 모델 API를 사용한다.

### 1. 설치

가장 간단한 설치는 한 줄이다.

```bash
uv tool install git+https://github.com/notx2wice/graphiti-folder.git
```

설치 확인과 업데이트는 다음 명령을 쓴다.

```bash
graphiti-folder --version
uv tool upgrade graphiti-folder
```

개발하려고 저장소를 직접 받은 경우에는 저장소 안에서 `uv tool install .`을
실행한다.

### 2. 로컬 Neo4j 시작

비밀번호를 정한 뒤 [공식 Neo4j Community 이미지](https://neo4j.com/docs/operations-manual/current/docker/introduction/)를
실행한다.

```bash
export GRAPHITI_FOLDER_NEO4J_PASSWORD='replace-with-a-long-password'
docker run --name graphiti-folder-neo4j \
  --restart unless-stopped \
  --detach \
  --publish 127.0.0.1:7474:7474 \
  --publish 127.0.0.1:7687:7687 \
  --env NEO4J_AUTH="neo4j/${GRAPHITI_FOLDER_NEO4J_PASSWORD}" \
  --volume graphiti-folder-neo4j-data:/data \
  neo4j:2026.06.0
```

저장소를 clone한 경우 같은 환경변수를 설정하고 `docker compose up -d neo4j`를 써도
된다. 브라우저 관리 화면은 `http://localhost:7474`, 프로그램 연결 주소는
`bolt://localhost:7687`이다.

### 3. 프로젝트 설정 만들기

```bash
cd /path/to/your/project
graphiti-folder init ./documents --project
```

프로젝트 루트에 다음 파일이 생긴다. 이 파일은 비밀값이 없으므로 저장소에 함께
커밋해도 된다.

```yaml
# graphiti-folder.yaml
version: 1
profile: your-project
group_id: your-project
sources:
  - path: ./documents
database:
  provider: neo4j
  uri: bolt://localhost:7687
  user: neo4j
  name: neo4j
```

이후 명령은 현재 폴더부터 상위 폴더로 올라가며 `graphiti-folder.yaml`을 자동으로
찾는다. 원본 경로는 YAML 위치를 기준으로 해석한다.

그래프는 Neo4j가 소유한다. 로컬에는 원본 처리 이력인 manifest만
`~/.graphiti-folder/profiles/your-project/state/manifest.sqlite3`에 저장된다.

여러 폴더를 함께 쓰려면 각 경로에 고유한 `name`을 붙인다.

```yaml
version: 1
profile: logkey
group_id: logkey
sources:
  - name: diary
    path: ./web/content/Private/Logkey
  - name: essays
    path: ../writing/essays
```

두 폴더에 `2026-08-02.md`가 모두 있어도 source ID는 각각
`diary/2026-08-02.md`, `essays/2026-08-02.md`가 되어 충돌하지 않는다. 같은 경로,
중복 name, 부모·자식으로 겹치는 경로는 설정 오류로 중단한다.

기존 단일 경로 설정에 두 번째 경로를 추가하는 경우에는 기존 항목 하나만 `name`을
생략할 수 있다. 그러면 과거 source ID를 유지하고 새 경로에만 namespace를 붙인다.
두 경로가 실제로 같은 source ID를 만들면 `plan`이 쓰기 전에 중단한다.

### 4. 비밀값 입력

`init` 출력에 표시된 profile 폴더의 `.env.example`을 `.env`로 복사한 뒤 모델 API
키와 2단계에서 정한 Neo4j 비밀번호를 입력한다. 위 예시라면
`~/.graphiti-folder/profiles/your-project/.env`다.

```dotenv
GRAPHITI_FOLDER_API_KEY=your-openrouter-key
GRAPHITI_FOLDER_NEO4J_PASSWORD=replace-with-a-long-password
```

`.env`는 Git이나 메신저에 올리지 않는다.

### 5. 준비 확인부터 첫 동기화까지

```bash
graphiti-folder doctor
graphiti-folder plan
graphiti-folder sync --limit 3
graphiti-folder status
graphiti-folder verify
```

각 명령의 질문은 하나뿐이다.

| 명령 | 답하는 질문 | API 비용 |
| --- | --- | --- |
| `doctor` | 지금 실행할 준비가 됐는가? | 없음 |
| `plan` | 어떤 문서가 추가·수정·제외되는가? | 없음 |
| `sync --limit 3` | 이번에 최대 3개를 실제로 넣을까? | 있음 |
| `status` | 원본·처리 기록·그래프의 현재 수치는? | 없음 |
| `verify` | 완료 기록이 실제 그래프에 모두 있는가? | 없음 |
| `search "질문"` | Graphiti가 어떤 Fact·Entity·Episode를 관련 맥락으로 찾는가? | 검색 임베딩 |

처음에는 `--limit 1` 또는 `--limit 3`을 권한다. 계획 전체를 정말 의도한 경우만
`sync --all`을 사용한다.

## 검색

검색은 Neo4j의 관계를 직접 전부 읽어 자체 점수를 매기지 않는다. Graphiti Core의 공식
고급 검색 API인 `Graphiti.search_()`와 검색 recipe를 그대로 사용한다.

```text
질문
  └─> Graphiti search_
        ├─ BM25 텍스트 검색
        ├─ 의미 벡터 검색
        └─ RRF 결과 결합
              └─> Fact(Edge) + Entity(Node) + Episode(원문 단위) + 출처
```

기본 `context` 검색은 넓은 질문에 필요한 Fact·Entity·Episode를 함께 반환한다.
`facts` 검색은 관계 Fact만 필요할 때 쓴다.

```bash
graphiti-folder search "요즘 바뀐 프로젝트 결정은?"
graphiti-folder search "이 판단은 과거와 어떻게 달라졌나?" --history --scope context
graphiti-folder search "최근 30일 심리 변화" \
  --since 2026-07-03 --until 2026-08-02 --history --limit 10
graphiti-folder search "Neo4j로 전환했다" --scope facts --limit 5
```

`--since`는 포함, `--until`은 미포함이다. 날짜만 적으면 UTC 자정으로 해석하므로
한국 시간 경계가 중요하면 `2026-07-03T00:00:00+09:00`처럼 시간대를 함께 적는다.
`--history`를 생략하면 현재 유효한 Fact만, 지정하면 만료·정정된 과거 Fact도 함께
찾는다. 변화나 기간 분석에는 보통 `--history`가 맞다.

시간 필터는 Graphiti의 시간 관계인 Fact에 직접 적용된다. Episode는 문서 시각으로
같은 기간을 한 번 더 제한한다. Entity는 여러 시점의 관계를 요약하는 노드이므로 기간
밖의 정보가 요약에 섞일 수 있다. 따라서 기간 분석의 직접 근거는 Fact와 Episode,
Entity는 탐색용 맥락으로 취급한다.

결과에는 원본 파일 경로와 revision이 함께 나온다. Graphiti는 관련 기억을 찾아주는
검색 계층이고, 최종 요약·심리 분석은 호출한 LLM이 검색 결과와 원문을 바탕으로 한다.
중요한 답은 반드시 반환된 원본을 다시 확인한다.

모든 검색은 profile 아래 `logs/search.jsonl`에 실행 시각, recipe, 기간, 결과 수,
source ID, 지연 시간과 오류를 한 줄씩 기록한다. 기본 위치는
`~/.graphiti-folder/profiles/<profile>/logs/search.jsonl`이며 권한은 `600`이다.
질문 원문도 로컬 로그에 남으므로 이 파일은 Git에 넣거나 공유하지 않는다.

## 문서가 바뀌면 어떻게 되는가

| 원본 변화 | 계획 표시 | 그래프 동작 |
| --- | --- | --- |
| 새 파일 | `ADD` | revision 1 episode 추가 |
| 기존 파일 수정 | `APPEND_REVISION` | 과거를 남기고 새 revision 추가 |
| 이전 실패와 같은 내용 | `RETRY` | revision을 늘리지 않고 재시도 |
| 변화 없음 | `SKIP` | 아무 작업도 하지 않음 |
| 빈 문서 | `SKIP_EMPTY` | 아무 작업도 하지 않음 |
| 원본 삭제 | `IGNORE_DELETED` | 기존 기억을 보존 |

삭제된 원본까지 그래프에서 지워야 하는 개인정보·법적 삭제 용도에는 이 정책이
맞지 않는다. 그 경우 원본을 정리한 뒤 별도 승인과 백업을 거쳐 새 DB를 만들어야
한다.

## Codex에서 읽기 전용 MCP로 사용

프로젝트 폴더에서 다음 명령을 실행하면 현재 YAML의 절대 경로가 들어간 설정
조각을 출력한다.

```bash
graphiti-folder mcp-config
```

MCP가 제공하는 도구는 `get_graphiti_status`, `search_graphiti`,
`get_episode_sources` 세 개다. 검색 도구 하나에서 `scope`, `start_time`, `end_time`,
`include_history`를 선택하므로 현재 검색과 과거 검색의 사용법이 갈라지지 않는다.
추가·삭제·초기화 도구는 노출하지 않는다. 문서 추가는 사용자가 비용 상한을 확인할
수 있는 CLI에서만 한다.

## 구조와 책임

```text
원본 폴더들 ──> scanner ──> 변경 계획 ──> 제한된 sync ──> Graphiti
                                │                          │
                                └──── manifest <───────────┘
                                                           │
질문 ──> CLI 또는 읽기 전용 MCP ──> Graphiti search_ ──> 맥락 + 원문 revision
```

| 구성요소 | 입력 | 출력과 책임 |
| --- | --- | --- |
| 원본 폴더 | 사람이 쓴 문서 | 단일 진실이며 이 도구는 수정하지 않는다. |
| scanner | 지원 확장자의 파일 | 본문, hash, 문서 시각, source ID를 만든다. |
| manifest | source ID와 hash | 어떤 revision을 어떤 episode로 처리했는지 기록한다. |
| Graphiti | 문서 revision | Entity와 시간 정보가 있는 Fact를 추출한다. |
| Neo4j | Graphiti 결과 | 네트워크 그래프 DB로 저장하고 동시 질의를 처리한다. |
| 읽기 전용 MCP | 질문·범위·기간 | Graphiti 검색 결과와 원문 revision 후보를 반환한다. |

여기서 **episode**는 Graphiti가 한 번에 읽는 출처 한 건, **Entity**는 사람·프로젝트·
장소 같은 대상, **Fact**는 Entity 사이의 관계를 나타내는 원문 기반 주장이다.

Graphiti는 upstream 지식 그래프 엔진이며 Entity·Fact 추출, 시간 관계, BM25·벡터
검색과 RRF 결합을 맡는다. 이 저장소가 추가한 부분은 폴더 탐색, 다중 경로 namespace,
revision manifest, 비용 상한이 있는 CLI, 기간 입력, 결과와 원본 경로 연결, 로컬 검색
로그, 읽기 전용 MCP와 배포 설정이다. 사용자 질문을 처리하는 검색 순위는 Graphiti의
recipe를 쓰며 이 저장소가 별도의 코사인·키워드 점수로 대체하지 않는다.

Neo4j 직접 조회는 `status`, `verify`, 중복 방지와 출처 무결성 같은 운영 확인에만
쓴다. 질문에 답할 기억을 고르는 경로에는 쓰지 않는다.

### 처리 시각

문서 시각은 다음 순서로 결정한다.

1. Markdown frontmatter의 `date`
2. 파일명의 `YYYY-MM-DD` 또는 `YYYY_MM_DD`
3. 파일 수정 시각

LLM이 문서 시각을 짐작해 정하지 않는다. Graphiti는 확정된 문서 시각과 본문을 받아
Fact의 시간 정보를 추출한다. 중요한 시간 정정은 원문에 명시해야 한다.

### 중단과 중복 방지

Graphiti 호출 전에 manifest 상태를 `pending`으로 기록하고, 성공한 episode UUID를
받은 뒤 `complete`로 바꾼다. 실패하면 `failed`다. episode 이름은 source ID,
revision, 본문 hash로 결정되므로 중단 뒤 재실행해도 기존 episode를 찾아 중복 생성을
피한다.

## 설정 전체

기본값까지 모두 펼친 YAML은 다음과 같다. 필요한 항목만 남겨도 된다.

```yaml
version: 1
profile: logkey
group_id: logkey

sources:
  - name: diary
    path: ./web/content/Private/Logkey
  - name: essays
    path: ../writing/essays

database:
  provider: neo4j
  uri: bolt://localhost:7687
  user: neo4j
  name: neo4j

extensions:
  - .md
  - .markdown
  - .txt

exclude_dirs:
  - .git
  - .venv
  - node_modules
  - archive

models:
  base_url: https://openrouter.ai/api/v1
  llm: openai/gpt-4.1-mini
  embedding: qwen/qwen3-embedding-8b
  embedding_dimensions: 1024

# 생략하면 ~/.graphiti-folder/profiles/logkey 사용
# data_dir: ~/.local/share/graphiti-folder/logkey
```

| 항목 | 의미 | 바꿀 때의 영향 |
| --- | --- | --- |
| `version` | 현재 설정 형식은 `1` | 지원하지 않는 버전은 즉시 중단한다. |
| `profile` | 개인 데이터 구분 이름 | 기본 manifest·`.env` 위치를 분리한다. |
| `group_id` | Graphiti 논리 그래프 이름 | 같은 Neo4j에서 프로젝트 데이터를 구분한다. |
| `sources` | 재귀 탐색할 원본 폴더 목록 | 상대 경로는 YAML 위치 기준이다. |
| `sources[].name` | source ID namespace | 여러 경로의 같은 상대 파일명 충돌을 막는다. |
| `extensions` | 읽을 확장자 | 점을 생략해도 정규화한다. |
| `exclude_dirs` | 제외할 폴더명 | 숨김 파일·폴더는 항상 제외한다. |
| `database.uri` | Neo4j Bolt URI | 로컬은 `bolt://`, Aura는 보통 `neo4j+s://`를 쓴다. |
| `database.user` | Neo4j 사용자 | 비밀번호는 YAML이 아닌 `.env`에 둔다. |
| `database.name` | Neo4j database | Community Edition 기본값은 `neo4j`다. |
| `models.*` | 추출·임베딩 모델 | 품질, 비용, 기존 그래프 호환성에 영향을 준다. |
| `data_dir` | 개인 파생 데이터 위치 | API 키와 manifest 저장 위치가 바뀐다. |
| `state.manifest` | 처리 기록 SQLite 경로 | 그래프를 새로 구축할 때 새 파일로 분리한다. |

새 다중 설정은 모든 source에 name을 붙이는 것이 권장값이다. 기존 source ID를 유지할
때만 source 하나의 name을 생략할 수 있다. 같은 경로를 두 번 넣거나 부모 폴더와 그
하위 폴더를 함께 넣으면 같은 파일을 두 번 처리할 수 있어 설정 단계에서 중단한다.
원본 밖을 가리키는 심볼릭 링크도 거부한다.

설정 선택 우선순위는 다음과 같다.

1. `--config /path/to/graphiti-folder.yaml`
2. `GRAPHITI_FOLDER_CONFIG`
3. `--home` 또는 `GRAPHITI_FOLDER_HOME`의 기존 `config.toml`
4. 현재 폴더부터 상위에서 발견한 `graphiti-folder.yaml`
5. 기존 `~/.graphiti-folder/config.toml`

특정 프로젝트를 명시하려면 전역 옵션을 명령 앞에 둔다.

```bash
graphiti-folder --config /path/to/graphiti-folder.yaml plan
```

이전 버전의 단일 경로 `config.toml`도 그대로 읽는다. 여러 경로가 필요하지 않으면
강제로 이전할 필요는 없다.

```toml
source_dir = "/absolute/path/to/documents"
group_id = "documents"

[database]
provider = "neo4j"
uri = "bolt://localhost:7687"
user = "neo4j"
name = "neo4j"
```

## 0.3 FalkorDB Lite에서 이전

0.4는 Neo4j 전용이다. 기존 `graphiti.db`를 삭제하거나 덮어쓰지 않지만 직접 변환해서
읽지도 않는다. Neo4j에는 원본 문서에서 episode를 다시 만들어야 하며 모델 비용이
발생한다.

기존 manifest를 그대로 사용하면 이미 완료된 문서가 `SKIP`되어 빈 Neo4j에 들어가지
않는다. 따라서 기존 파일을 보존하고 Neo4j용 manifest를 새 경로로 지정한다.

```yaml
database:
  provider: neo4j
  uri: bolt://localhost:7687
  user: neo4j
  name: neo4j

state:
  manifest: state/manifest-neo4j.sqlite3
```

그 다음 `plan`에서 기존 문서가 `ADD`로 표시되는지 확인한다. 실제 재구축은 처음부터
전체 실행하지 말고 `sync --limit 1`로 Neo4j 저장과 `verify`를 확인한 뒤 범위를 늘린다.
기존 FalkorDB 파일과 manifest는 전환 검증이 끝날 때까지 보존한다.

## 0.5 검색 방식 변경

0.4까지의 자체 검색은 Neo4j의 Fact를 직접 읽은 뒤 Python에서 코사인 유사도와
키워드 점수를 계산했다. 0.5부터 이 경로는 제거됐고 공식 Graphiti `search_()`와
`COMBINED_HYBRID_SEARCH_RRF` 또는 `EDGE_HYBRID_SEARCH_RRF` recipe를 사용한다.

MCP의 `search_current_facts`, `search_fact_history`도 `search_graphiti` 하나로
통합됐다. 기존 MCP 클라이언트에서 도구 이름을 직접 지정했다면 새 이름과
`include_history` 옵션으로 바꾼다.

## 반복 운영과 문제 해결

평소에는 다음 순서만 반복한다.

```bash
graphiti-folder doctor
graphiti-folder plan
graphiti-folder sync --limit 3
graphiti-folder status
graphiti-folder verify
```

자주 쓰는 범위 제한은 다음과 같다.

```bash
# 최신 문서 최대 1개
graphiti-folder sync --limit 1

# source ID에 journal이 들어간 문서 최대 5개
graphiti-folder sync --limit 5 --path-contains journal

# 한 파일이 실패해도 선택된 다음 파일 계속
graphiti-folder sync --limit 5 --continue-on-error

# 계획 전체를 의도적으로 처리
graphiti-folder sync --all
```

`plan`, `status`, `verify`, `search`는 자동화용 `--json` 출력을 지원한다. 검색 로그를
간단히 확인하려면 다음처럼 실행한다.

```bash
tail -n 5 ~/.graphiti-folder/profiles/your-project/logs/search.jsonl | jq .
```

| 화면의 문제 | 먼저 확인할 것 | 다음 행동 |
| --- | --- | --- |
| 설정 파일 없음 | 프로젝트 루트와 현재 위치 | 프로젝트 루트에서 `init --project` 실행 |
| 원본 폴더 없음 | `sources[].path` | YAML 위치 기준으로 경로 수정 |
| source name 오류 | 여러 source의 `name` | 고유한 영문·숫자·하이픈·밑줄 이름 지정 |
| 읽을 문서 0개 | 확장자와 제외 폴더 | `.md`, `.markdown`, `.txt` 존재 확인 |
| Neo4j 비밀번호 없음 | profile 폴더의 `.env` | `GRAPHITI_FOLDER_NEO4J_PASSWORD` 입력 |
| Neo4j 연결 실패 | URI·서버·인증 | 컨테이너 상태 또는 Aura 연결 주소 확인 |
| API 키 없음 | profile 폴더의 `.env` | `GRAPHITI_FOLDER_API_KEY` 입력 |
| 파일 하나 실패 | `status`의 failed 수 | 원인을 고친 뒤 제한을 둬 재실행 |
| `missing_episode_uuids` | Neo4j와 manifest | 같은 프로젝트 쌍인지 확인 후 쓰기 중단 |
| sync 잠금 대기 | 다른 sync 프로세스 | 진행 중인 동기화가 끝날 때까지 대기 |

`zero_fact_episode_uuids`는 episode는 있으나 추출된 Fact가 0개라는 품질 경고다.
Neo4j와 manifest는 같은 논리 상태로 백업한다. manifest와 비밀값은 Git에 넣지 않는다.

## AWS에 원격 MCP 배포

Terraform 구성은 private S3의 원본 사본, EFS의 manifest, ECS Fargate의 읽기 전용
MCP를 만든 뒤 외부 Neo4j에 연결한다. Neo4j 자체는 Terraform이 만들지 않는다. Aura나
별도로 운영하는 Neo4j의 TLS Bolt URI를 입력한다. 현재 컨테이너는 `linux/amd64` 기준으로
검증한다.

```text
내 문서 ──aws s3 sync──> private S3 ──mirror──> EFS 문서·manifest
                                                   │
동기화 task ──sync --limit N───────────────────────┼──> Neo4j/Aura
                                                   │
클라이언트 ──HTTPS ALB──> 인증된 MCP 1 task ──────┘
```

기본 안전장치는 다음과 같다.

- `/mcp`는 bearer token으로 인증하고 `/healthz`만 인증 없이 확인한다.
- API 키, MCP token, Neo4j 비밀번호는 AWS Secrets Manager에 둔다.
- S3는 public access를 막고 versioning을 켠다.
- EFS는 원본 mirror와 manifest에만 사용하며 저장·전송 암호화와 백업 정책을 적용한다.
- Graphiti 쓰기는 별도 task의 명시적인 `sync --limit N`에서만 일어난다.

필요한 것은 Terraform 1.6 이상, 인증된 AWS CLI, Route 53 public hosted zone,
ECS에서 접근 가능한 Neo4j URI, OpenRouter API 키 secret ARN, MCP bearer token secret
ARN, Neo4j 비밀번호 secret ARN이다. Aura는 `neo4j+s://` URI를 사용한다. secret의 실제
값은 Terraform 변수에 넣지 않는다.

### 1. 인프라 생성

```bash
cd deploy/aws
cp terraform.tfvars.example terraform.tfvars
# domain, hosted zone, Neo4j URI, 세 secret ARN 입력
terraform init
terraform plan
terraform apply
```

ALB, Fargate, EFS와 외부 Neo4j는 계속 비용이 발생할 수 있다. 적용 전 Terraform plan과
각 서비스 가격을 확인한다.

### 2. 문서 업로드

```bash
BUCKET=$(terraform output -raw documents_bucket)
aws s3 sync /absolute/path/to/documents "s3://${BUCKET}/documents/" --delete

CLUSTER=$(terraform output -raw ecs_cluster_name)
SERVICE=$(terraform output -raw ecs_service_name)
aws ecs update-service --cluster "$CLUSTER" --service "$SERVICE" --force-new-deployment
```

S3 동기화만으로 Graphiti 쓰기는 일어나지 않는다.

### 3. 최대 5개 동기화 task 실행

```bash
CLUSTER=$(terraform output -raw ecs_cluster_name)
TASK=$(terraform output -raw sync_task_definition_arn)
SUBNETS=$(terraform output -json public_subnet_ids | jq -r 'join(",")')
SG=$(terraform output -raw task_security_group_id)

aws ecs run-task \
  --cluster "$CLUSTER" \
  --task-definition "$TASK" \
  --launch-type FARGATE \
  --platform-version 1.4.0 \
  --network-configuration "awsvpcConfiguration={subnets=[$SUBNETS],securityGroups=[$SG],assignPublicIp=ENABLED}" \
  --overrides '{"containerOverrides":[{"name":"graphiti-folder","command":["graphiti-folder","--home","/data","sync","--limit","5"]}]}'
```

로그는 `/ecs/graphiti-folder` CloudWatch Logs에서 확인한다. Neo4j는 검색과 쓰기를
동시에 처리하지만, 중복 동기화를 막기 위해 sync task는 한 번에 하나만 실행한다.

### 4. 원격 MCP 확인

```bash
terraform output -raw mcp_url
fastmcp list "$(terraform output -raw mcp_url)" --auth "Bearer YOUR_MCP_TOKEN"
```

token을 URL, Git, Terraform 변수, 로그에 넣지 않는다. secret을 교체한 뒤에는 ECS
service를 새로 배포해야 새 task가 값을 받는다. 제거 전에는 Neo4j backup, EFS manifest,
필요한 S3 version을 확인한다. `documents_bucket_force_destroy=false`가 기본이라 문서가
남은 bucket은 자동 삭제되지 않는다.

## 개발과 검증

```bash
git clone https://github.com/notx2wice/graphiti-folder.git
cd graphiti-folder
uv sync
uv run ruff check src tests
uv run pytest -q
```

테스트는 다중 source namespace, 생성·수정·삭제·재생성 lifecycle, 실패 재시도,
Graphiti recipe·group·시간 필터·출처 연결·검색 로그, 읽기 전용 MCP, 컨테이너와
Terraform 안전 조건을 포함한다.

## 현재 경계와 앞으로 할 일

현재 경계:

- 로컬에서도 별도 Neo4j 서버가 필요하다. 가장 짧은 경로는 Docker Community Edition이다.
- 검증된 기본 조합은 Graphiti Core 0.29.3, `openai/gpt-4.1-mini`,
  `qwen/qwen3-embedding-8b`다.
- LLM은 암묵적인 정정을 모두 찾지 못한다. 중요한 변경은 “이전 판단은 더 이상
  유효하지 않다”처럼 원문에 명시한다.
- 원본 삭제는 기억 삭제가 아니다. 개인정보·법적 삭제는 새 DB 재구성과 교체 검증이
  필요한 별도 작업이다.
- Terraform은 Neo4j를 생성하지 않으므로 Aura 또는 별도 서버의 백업·가용성은 사용자가
  선택한 서비스 정책을 따른다.
- 현재 ECS 서비스는 EFS manifest와 문서 mirror를 공유하므로 MCP task를 1개로 유지한다.

앞으로 할 일:

- YAML 설정 형식의 실제 사용 사례를 더 모아 오류 메시지와 migration 경험 개선
- manifest를 네트워크 저장소로 옮겨 MCP 다중 replica 지원
- 모델 호출 비용과 문서별 처리 시간을 status에서 더 쉽게 비교
- 민감정보 제거용 승인·백업·전체 재구성 절차를 일상 CLI와 분리해 설계

Upstream: [getzep/graphiti](https://github.com/getzep/graphiti)

TDQS

A4.4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: status retrieval, search, and episode source resolution. No functional overlap.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern (get_*, search_*) with domain-specific suffixes, making names predictable and clear.

Tool Count5/5

Three tools is a focused, well-scoped set for a Graphiti folder server, covering essential read/search operations without redundancy.

Completeness4/5

Core operations for querying status, searching, and retrieving episode sources are present. Minor gaps like graph traversal or metadata listing are absent but not critical for the apparent purpose.

Maintenance

ActivitySlowing
ResponsivenessNo issues