Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.api.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Must match the password portion of NEO4J_AUTH in .env.
NEO4J_PASSWORD=local-knowledge-only
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Local development credentials. Change both example-derived files together for shared deployments.
NEO4J_AUTH=neo4j/local-knowledge-only
109 changes: 109 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: CI

on:
pull_request:
branches: [main]
push:
branches: [main]

permissions:
contents: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
server:
name: Server tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Install uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "0.12.0"
python-version: "3.13"
- name: Run server tests
run: uv run --frozen --project server pytest server/tests -q

web:
name: Web tests and build
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
cache: npm
cache-dependency-path: web/package-lock.json
- name: Install dependencies
run: npm ci
working-directory: web
- name: Audit dependencies
run: npm audit --audit-level=high
working-directory: web
- name: Run web tests
run: npm test -- --run
working-directory: web
- name: Build production bundle
run: npm run build
working-directory: web

compose:
name: Compose config
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Validate Compose configuration
run: |
test -f .env || cp .env.example .env
test -f .env.api || cp .env.api.example .env.api
python3 - <<'PY'
from pathlib import Path

def read_value(path: str, key: str) -> str:
for raw in Path(path).read_text().splitlines():
line = raw.strip()
if line and not line.startswith("#") and line.startswith(f"{key}="):
return line.split("=", 1)[1]
raise SystemExit(f"missing {key} in {path}")

auth = read_value(".env.example", "NEO4J_AUTH")
password = read_value(".env.api.example", "NEO4J_PASSWORD")
assert auth.startswith("neo4j/") and auth.split("/", 1)[1] == password
PY
docker compose config --quiet

release-ready:
name: Release ready
if: ${{ always() }}
needs: [server, web, compose]
runs-on: ubuntu-latest
timeout-minutes: 2
env:
SERVER_RESULT: ${{ needs.server.result }}
WEB_RESULT: ${{ needs.web.result }}
COMPOSE_RESULT: ${{ needs.compose.result }}
steps:
- name: Require every release gate
run: |
test "$SERVER_RESULT" = success
test "$WEB_RESULT" = success
test "$COMPOSE_RESULT" = success
61 changes: 61 additions & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,20 @@ OKF Markdown ──> FastAPI cataloger ──> PostgreSQL + pgvector ──> Rea
```bash
git clone https://github.com/hungrytech/knowledge-wiki.git
cd knowledge-wiki
test -f .env || cp .env.example .env
test -f .env.api || cp .env.api.example .env.api
docker compose up -d --build
docker compose ps
curl -fsS http://localhost:8000/api/health
```

サンプル認証情報はローカル専用です。共有環境または非ローカル環境へデプロイする前に強いパスワードへ変更し、`.env` の `NEO4J_AUTH` に含まれるパスワード部分と `.env.api` の `NEO4J_PASSWORD` を同じ値に保ってください。

```dotenv
NEO4J_AUTH=neo4j/replace-with-a-strong-password
NEO4J_PASSWORD=replace-with-a-strong-password
```

- Wiki browser: <http://localhost:5173>
- API: <http://localhost:8000/api>
- PostgreSQL: `localhost:5433`(ローカル開発専用)
Expand Down Expand Up @@ -77,6 +86,57 @@ data/wiki/

`Source` は外部資料と provenance を保存し、`Concept` と `Comparison` は解釈を記録します。この境界により主張をレビュー可能にし、根拠を黙って書き換えることを防ぎます。

### 型付きコンテキスト関係

長期記憶文書は、frontmatter に方向と種類を持つ関係を記録できます。短縮形式は既存 corpus の規約に合い、構造化形式では edge 単位の根拠や時刻も保持できます。

```yaml
relations:
- "supported-by [[sources/primary-evidence]]"
- kind: supersedes
target: concepts/previous-decision
context: ADR-0042
timestamp: 2026-07-26T10:30:00Z
```

本文の内部リンクは `links-to`、frontmatter の関係は明示された kind として投影されます。UI の **コンテキスト** グラフは選択文書の incoming/outgoing edge を表示します。Neo4j は再構築可能な派生物であり、Markdown の関係が正本です。

### コンテキストが長く使える知識へ昇格する流れ

グラフに線ができただけでは、信頼できる知識にはなりません。WikiBrain は一時的な観察が暗黙に永続的な事実へ変わらないよう、収集、解釈、利用を分けます。

| 段階 | 意味 | 代表的な文書・関係 |
|---|---|---|
| 0. 入口 | 会話、URL、handoff、観察がまだ知識として採用されていない | curator が収集するまでは正本 bundle の外に置く |
| 1. 根拠 | URL、時刻、hash とともに原文を保存する | `Source` |
| 2. 理解 | 主張を簡潔に整理し、根拠と照合する | `supported-by` で結んだ `Concept` または `Comparison` |
| 3. 利用 | レビュー済みの知識を実装や長期的な判断に使う | `Project` または判断用 `Concept` と、`extends`・`adopts` などの明示的な関係 |
| 4. 更新 | 新しい根拠で以前の結論を改めても、履歴は消さない | 新文書から旧文書への `supersedes` |

現在の昇格は人によるレビューで行います。Curator が出典を確認し、重複を除き、事実と解釈を分けてから関係を明示します。グラフには、長期文書が作られた理由と、何を置き換えたかが残ります。

```mermaid
flowchart LR
A[会話、URL、<br/>handoff、観察] -->|curator が収集| B[Source<br/>変更しない原文根拠]
B --> C{出典があり<br/>関連性と可読性が十分か?}
C -- いいえ --> X[長期 corpus の外に置くか<br/>より良い根拠を求める]
C -- はい --> D[Concept または Comparison<br/>整理した理解]
D -->|supported-by| B
D --> E{レビュー済みで<br/>今後も役立つか?}
E -- まだ --> D
E -- はい --> F[Project または長期的な<br/>判断用 Concept]
F -->|extends / adopts| D
G[新しい根拠] --> H[新しい解釈]
H -->|supersedes| D
H --> F
```

#### 現在実装されていること

WikiBrain は型付き関係を解析・保存し、`/api/graph` で返し、Neo4j が有効なら派生グラフへ投影します。UI では選択文書の incoming/outgoing 関係を確認できます。Markdown が正本で、PostgreSQL と Neo4j は再構築できます。

現在、会話 session の自動収集、保持期間の計算、人気スコアによる自動昇格、関係種類の推論は行いません。`brainctl remember` コマンドも存在しません。自動昇格は将来の機能です。実装する場合は provenance の保持、競合の可視化、レビュー可能な方針を先に整え、その後に正本 Markdown を変更する必要があります。

## 開発

```bash
Expand All @@ -89,6 +149,7 @@ npm --prefix web run build

- **ローカル利用**を前提としています。API、DB ポート、Compose の認証情報を公衆インターネットへ公開しないでください。
- Compose の PostgreSQL パスワードは開発用プレースホルダーです。共有/本番環境では変更し、シークレット管理を使用してください。
- URL 取り込みは、検証済みの公開 IPv4 ターゲットにのみ接続します。IPv6-only/NAT64 ターゲット、圧縮レスポンス、5 MiB を超えるレスポンス、全体で 20 秒の deadline を超える取得は拒否します。取り込んだ内容を信頼する前に、出典と本文を確認してください。
- 公開 fork 前に `data/wiki/` に個人メモやライセンス制限のある内容がないか確認してください。

## ロードマップ
Expand Down
61 changes: 61 additions & 0 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,20 @@ OKF Markdown ──> FastAPI cataloger ──> PostgreSQL + pgvector ──> Rea
```bash
git clone https://github.com/hungrytech/knowledge-wiki.git
cd knowledge-wiki
test -f .env || cp .env.example .env
test -f .env.api || cp .env.api.example .env.api
docker compose up -d --build
docker compose ps
curl -fsS http://localhost:8000/api/health
```

예제 자격 증명은 로컬 전용입니다. 공유 환경이나 비로컬 환경에 배포하기 전에는 강한 비밀번호로 교체하고, `.env`의 `NEO4J_AUTH` 비밀번호 부분과 `.env.api`의 `NEO4J_PASSWORD`를 같게 유지하세요.

```dotenv
NEO4J_AUTH=neo4j/replace-with-a-strong-password
NEO4J_PASSWORD=replace-with-a-strong-password
```

- Wiki browser: <http://localhost:5173>
- API: <http://localhost:8000/api>
- PostgreSQL: `localhost:5433` — 로컬 개발 전용
Expand Down Expand Up @@ -80,6 +89,57 @@ data/wiki/

`Source`는 외부 원문과 provenance를 보관하고, `Concept`와 `Comparison`은 해석을 기록합니다. 이 경계를 유지하면 주장 검토가 쉬우며 근거를 조용히 바꾸지 않게 됩니다.

### 타입이 있는 맥락 관계

장기기억 문서는 frontmatter에 방향과 종류가 있는 관계를 기록할 수 있습니다. 짧은 형식은 기존 corpus 관례이고, 구조화 형식은 edge 수준의 근거나 시간을 함께 보존합니다.

```yaml
relations:
- "supported-by [[sources/primary-evidence]]"
- kind: supersedes
target: concepts/previous-decision
context: ADR-0042
timestamp: 2026-07-26T10:30:00Z
```

본문 내부 링크는 `links-to`로, frontmatter 관계는 명시한 kind로 projection됩니다. UI의 **맥락** 그래프는 선택 문서의 incoming/outgoing edge를 보여 줍니다. Neo4j는 재생성 가능한 파생물이고 Markdown 관계가 정본입니다.

### 맥락이 오래 쓰는 지식으로 승급되는 과정

그래프 선이 생겼다고 곧바로 믿을 만한 지식이 되는 것은 아닙니다. WikiBrain은 임시 관찰이 조용히 영구 사실로 굳지 않도록 수집, 해석, 활용을 나눕니다.

| 단계 | 의미 | 대표 문서·관계 |
|---|---|---|
| 0. 입구 | 대화, URL, handoff, 관찰이 아직 지식으로 채택되지 않은 상태 | curator가 수집하기 전에는 정본 bundle 밖에 둠 |
| 1. 근거 | URL, 시각, hash와 함께 원문을 보존 | `Source` |
| 2. 이해 | 주장을 짧게 정리하고 근거와 대조 | `supported-by`로 연결한 `Concept` 또는 `Comparison` |
| 3. 활용 | 검토한 지식이 구현이나 오래 유지할 의사결정에 쓰임 | `Project` 또는 의사결정 중심 `Concept`, `extends`·`adopts` 등 명시적 관계 |
| 4. 갱신 | 새 근거가 이전 결론을 바꾸되 과거 기록은 지우지 않음 | 새 문서가 이전 문서를 `supersedes`로 연결 |

현재 승급은 사람이 검토하는 과정입니다. Curator가 출처를 확인하고, 중복을 제거하고, 사실과 해석을 분리한 뒤 관계를 직접 기록합니다. 그래프는 장기 문서가 왜 생겼고 무엇을 대신했는지 남깁니다.

```mermaid
flowchart LR
A[대화, URL,<br/>handoff, 관찰] -->|curator가 수집| B[Source<br/>바꾸지 않는 원문 근거]
B --> C{출처가 남아 있고<br/>관련성과 가독성이 충분한가?}
C -- 아니오 --> X[장기 corpus 밖에 두거나<br/>더 나은 근거 요청]
C -- 예 --> D[Concept 또는 Comparison<br/>정제한 이해]
D -->|supported-by| B
D --> E{검토를 마쳤고<br/>나중에도 쓸 만한가?}
E -- 아직 아님 --> D
E -- 예 --> F[Project 또는 오래 유지할<br/>의사결정 Concept]
F -->|extends / adopts| D
G[새 근거] --> H[새 해석]
H -->|supersedes| D
H --> F
```

#### 지금 실제로 되는 것

WikiBrain은 타입 관계를 읽고 보존하며, `/api/graph`로 반환하고, Neo4j가 켜져 있으면 파생 그래프에 투영합니다. UI에서는 선택 문서의 들어오는 관계와 나가는 관계를 볼 수 있습니다. Markdown이 정본이고 PostgreSQL과 Neo4j는 다시 만들 수 있습니다.

현재는 대화 session을 자동 수집하거나, 보존 기간을 계산하거나, 인기 점수로 자동 승급하거나, 관계 종류를 추론하지 않습니다. `brainctl remember` 명령도 없습니다. 자동 승급은 향후 기능입니다. 구현하려면 provenance 보존, 충돌 노출, 검토 가능한 정책을 먼저 갖추고 나서 정본 Markdown을 변경해야 합니다.

## 개발

```bash
Expand All @@ -92,6 +152,7 @@ npm --prefix web run build

- 이 프로젝트는 **로컬 사용**을 목표로 합니다. API, DB 포트, Compose 자격 증명을 인터넷에 노출하지 마세요.
- Compose PostgreSQL 비밀번호는 개발용 placeholder입니다. 공유/운영 배포 전에는 변경하고 secret 관리를 사용하세요.
- URL 수집은 검증된 공개 IPv4 대상에만 연결합니다. IPv6-only/NAT64 대상, 압축 응답, 5 MiB 초과 응답, 전체 20초 deadline을 넘는 수집은 거부합니다. 캡처한 내용을 신뢰하기 전에 출처와 본문을 검토하세요.
- 공개 fork 전에 `data/wiki/`에 개인 노트나 라이선스가 제한된 자료가 없는지 검토하세요.

## 로드맵
Expand Down
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,20 @@ Markdown remains canonical; deleting the derived database does not lose knowledg
git clone https://github.com/hungrytech/knowledge-wiki.git
cd knowledge-wiki

test -f .env || cp .env.example .env
test -f .env.api || cp .env.api.example .env.api
docker compose up -d --build
docker compose ps
curl -fsS http://localhost:8000/api/health
```

The example credentials are for local use only. Before a shared or non-local deployment, replace them with a strong password and keep the password portion of `NEO4J_AUTH` in `.env` equal to `NEO4J_PASSWORD` in `.env.api`:

```dotenv
NEO4J_AUTH=neo4j/replace-with-a-strong-password
NEO4J_PASSWORD=replace-with-a-strong-password
```

Open:

- **Wiki browser:** <http://localhost:5173>
Expand Down Expand Up @@ -131,6 +140,57 @@ data/wiki/

A `Source` document preserves external material and provenance. A `Concept` or `Comparison` document adds interpretation. Keeping these separate makes claims reviewable and lets the corpus evolve without silently rewriting source evidence.

### Typed context relations

Durable context can declare directed, typed relations in frontmatter. The compact form matches the corpus's existing convention; the structured form adds edge-level provenance or time metadata:

```yaml
relations:
- "supported-by [[sources/primary-evidence]]"
- kind: supersedes
target: concepts/previous-decision
context: ADR-0042
timestamp: 2026-07-26T10:30:00Z
```

Internal Markdown links are projected as `links-to`; frontmatter relations keep their explicit kind. The UI's **Context** graph shows incoming and outgoing edges around the selected document. Neo4j remains a rebuildable projection—the Markdown relation is canonical.

### How context becomes durable knowledge

A graph edge does not make a note trustworthy. WikiBrain separates capture, interpretation, and action so a temporary observation does not silently become a durable fact.

| Stage | What it means | Typical document or relation |
|---|---|---|
| 0. Intake | A conversation, URL, handoff, or observation has not been accepted as knowledge yet | Outside the canonical bundle until a curator captures it |
| 1. Evidence | The original material is captured with its URL, time, and hash | `Source` |
| 2. Understanding | A claim is distilled, checked, and connected to its evidence | `Concept` or `Comparison` with `supported-by` |
| 3. Use | Reviewed knowledge informs an implementation or durable decision | `Project`, or a decision-focused `Concept`, linked with `extends`, `adopts`, or another explicit kind |
| 4. Revision | New evidence changes an older conclusion without rewriting history | A new document with `supersedes`; the old document remains traceable |

Promotion is review-driven today. A curator checks provenance, removes duplicates, separates fact from interpretation, and writes the relation explicitly. The graph records why the durable document exists and what it replaced.

```mermaid
flowchart LR
A[Conversation, URL,<br/>handoff, or observation] -->|curator captures| B[Source<br/>immutable evidence]
B --> C{Provenance present?<br/>Relevant and readable?}
C -- No --> X[Keep outside the durable corpus<br/>or request better evidence]
C -- Yes --> D[Concept or Comparison<br/>distilled understanding]
D -->|supported-by| B
D --> E{Reviewed and useful<br/>for future work?}
E -- Not yet --> D
E -- Yes --> F[Project or durable<br/>decision Concept]
F -->|extends / adopts| D
G[New evidence] --> H[New interpretation]
H -->|supersedes| D
H --> F
```

#### What is implemented now

WikiBrain parses and preserves typed relations, returns them from `/api/graph`, projects them into Neo4j when enabled, and renders incoming and outgoing context in the UI. Markdown remains canonical; PostgreSQL and Neo4j can be rebuilt.

WikiBrain does **not** currently ingest chat sessions automatically, run a retention clock, calculate a popularity score, infer relation kinds, or provide a `brainctl remember` command. Automatic promotion may be added later, but it must retain provenance, expose conflicts, and require a reviewable policy before it can change canonical Markdown.

## Development

```bash
Expand All @@ -153,7 +213,7 @@ docker compose exec -T postgres psql -U knowledge -d knowledge_wiki -Atc \

- This project is designed for **local use**. Do not expose the API, database port, or Docker Compose credentials directly to the public internet.
- The Compose PostgreSQL password is a development-only placeholder. Replace it and use managed secret handling before any shared or production deployment.
- URL ingestion should remain restricted to public addresses; preserve sources and inspect fetched content before trusting it.
- URL ingestion connects only to validated public IPv4 targets. IPv6-only/NAT64 targets, compressed responses, responses over 5 MiB, and fetches exceeding the 20-second total deadline are rejected. Preserve sources and inspect fetched content before trusting it.
- Knowledge may contain personal notes or licensed material. Review `data/wiki/` before making a fork or derivative repository public.

## Roadmap
Expand Down
Loading