# Daemon 生命週期

`kura` 如何啟動背景 daemon、daemon 在啟動與關閉時做什麼，以及就緒偵測與停止的運作方式。

## 啟動流程

執行 `kura` 會以 `kura --daemon` 在新的 session（`setsid`）中重新執行同一個執行檔，stdin 綁定 `/dev/null`，stdout 與 stderr 附加寫入 `~/.config/kuradb/daemon.log`。父程序接著每 100 ms 檢查 `~/.config/kuradb/endpoint`，內容一非空就印出。

daemon 內部依序：

1. 寫入 `runtime.uid`，內含新的 UUID、PID 與啟動時間。
2. 載入 `db.json`；讀取失敗則 daemon 結束。
3. 對每個已註冊資料庫：確認 `<name>/` 與 `<name>/inbox/` 存在、修復 `~/Kura_<name>` symlink、開啟 `data.db`，並啟動其 watcher。任一步驟失敗的資料庫會記錄後略過。
4. 啟動 HTTP 伺服器並寫入 `endpoint`。

## HTTP Listener

| 設定 | 值 |
|---|---|
| 綁定位址 | `127.0.0.1` |
| 連接埠（固定） | `config.json` 的 `port`；無法綁定時 HTTP 伺服器不會啟動，`kura` 回報 daemon 未在 10 秒內就緒 |
| 連接埠（隨機） | 在 10000 到 65535 之間均勻挑選，最多嘗試 10 次 |
| 讀取標頭逾時 | 5 秒 |
| `/mcp` 路由 | 啟動時 `config.json` 的 `remote` 為 `true` 才掛載 |

## 關閉

`SIGINT` 或 `SIGTERM` 會取消 daemon context。HTTP 伺服器移除 `endpoint` 並以 5 秒寬限期關閉，各 watcher 結束，刪除 `runtime.uid`，並關閉所有 SQLite 連線。

`kura stop` 從 `runtime.uid` 讀取 PID，送出 `SIGTERM`，每 100 ms 檢查一次、最多等 5 秒，程序仍存活就送出 `SIGKILL`。`runtime.uid` 不存在時以 `no running daemon found` 結束、PID 已不存在時以 `daemon not running` 結束，結束碼皆為 1。

## 日誌

`daemon.log` 接收 daemon 輸出的結構化 `slog` 紀錄：

| 紀錄 | 意義 |
|---|---|
| `db: ready db=<name>` | 資料庫已開啟、watcher 已啟動 |
| `http server url=... remote_mcp=<bool>` | Listener 已啟動 |
| `changed path=...` | watcher 偵測到新增或修改的項目 |
| `saved kind=... path=... chunks=<n>` | 檔案已索引 |
| `dismissed path=...` | 已移除檔案的資料列已隱藏 |
| `shutdown reason=...` | daemon 正在停止 |

## 相關頁面

- [設定](/zh/configuration)
- [資料配置](/zh/data-layout)
- [CLI 指令](/zh/cli-reference)
