0. プロジェクトのセットアップ
Bun + TypeScript のプロジェクトを初期化し、QVAC をインストールし、以降のウォークスルーで使う開発ツールを固定する。
ソースファイルを書く前に、動作する Bun + TypeScript のプロジェクトが
必要です。このステップは 1 分ほどで終わり、後の src/cli.ts と
src/server.ts が走る土台ができます。
前提条件
- Bun
>=1.3.0(インストール) - Node
>=22.17.0(TypeScript と一部のnode:モジュールが使用)
OpenAI のキーも、Pinecone のアカウントも、GPU も不要です。すべてが QVAC を 通してローカルで動きます。
1. プロジェクトを作る
mkdir locallens
cd locallens
bun init -ybun init -y は最小限の package.json、tsconfig.json、.gitignore、
そしてプレースホルダの index.ts を書き出します。index.ts は削除して
ください。本物のエントリポイント(src/cli.ts、src/server.ts)は後で
作ります。
2. 依存をインストールする
bun add @qvac/sdk
bun add -d typescript @types/bun @biomejs/biomeそれぞれの用途は次のとおりです。
| パッケージ | 用途 |
|---|---|
@qvac/sdk | ローカル AI ループ: モデル読み込み、RAG、テキスト生成。LocalLens 唯一のランタイム依存。 |
typescript | これから書く 8 ファイルに対する strict 型チェック。 |
@types/bun | Bun.argv、Bun.serve、Bun.file、import.meta.dir の型定義。 |
@biomejs/biome | lint とフォーマットの一体型ツール。ESLint + Prettier の代わり。 |
依存の全体はこれだけです。ベクトルデータベースも、埋め込みライブラリも、 チャンク分割器もありません。
3. ランタイムバージョンを固定する
作られたばかりの package.json を開き、type: "module" と engines
フィールドを設定します。これでリポジトリをクローンする誰もが同じ
ランタイムで動かせます。
{
"name": "locallens",
"version": "0.1.0",
"type": "module",
"private": true,
"license": "MIT",
"engines": {
"bun": ">=1.3.0",
"node": ">=22.17.0"
}
}4. 使うスクリプトを追加する
これらを package.json に追加します。それぞれ後のステップで配線され
ますが、今は存在するだけで十分です。
{
"scripts": {
"cli": "bun run src/cli.ts",
"dev": "bun run src/server.ts",
"start": "bun run src/server.ts",
"build": "bun build src/server.ts --target=bun --outdir=dist",
"test": "bun test",
"typecheck": "tsc --noEmit",
"lint": "biome check .",
"format": "biome format --write .",
"check": "bun run lint && bun run typecheck && bun run test && bun run build"
}
}bun run check は CI が使う複合コマンドです。lint → 型 → テスト →
ビルドの順に走り、どこかで失敗すれば非ゼロで終了します。
5. tsconfig.json を引き締める
bun init は妥当なデフォルトを出力しますが、このウォークスルーでは
追加で 2 つほど必要なものがあります。strict mode、Bun の型、そして
.ts 拡張子を明示的に import できる設定です。生成されたファイルを
次の内容で置き換えてください。
{
"compilerOptions": {
"target": "ES2023",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["bun"],
"allowImportingTsExtensions": true,
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true
},
"include": ["src/**/*.ts", "tests/**/*.ts"]
}特筆しておきたいフラグが 2 つあります。
allowImportingTsExtensions: trueを有効にすると、ソースにimport "./domain.ts"と書けます。Bun はそのまま実行できますし、 明示的な拡張子はtscを満足させます。verbatimModuleSyntax: trueは、型だけの import にimport typeを 要求します。このウォークスルーのコードはその書き方になっており、 このフラグでそれを強制します。
6. Biome を設定する
Biome が lint とフォーマットの両方を担当します。設定ファイルは 1 つ だけです。
{
"$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
"files": {
"includes": ["**", "!dist", "!node_modules", "!.locallens"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": { "recommended": true }
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"semicolons": "always",
"trailingCommas": "all"
}
}
}!.locallens の除外は、アプリが動き出すと効いてきます。このフォルダは
JSON ストアと brain データが置かれる場所で、Biome がフォーマットしようと
してはいけません。
7. QVAC を設定する
QVAC はランタイム設定をリポジトリルートの qvac.config.json から
読み込みます。ゲートウェイがロードできるよう、今ここで作っておきます。
{
"loggerLevel": "info",
"loggerConsoleOutput": true,
"httpDownloadConcurrency": 3,
"serve": {
"models": {
"locallens-chat": {
"model": "QWEN3_1_7B_INST_Q4",
"default": true,
"preload": false,
"config": {
"ctx_size": 4096,
"temp": 0.2,
"top_p": 0.9
}
},
"locallens-embed": {
"model": "GTE_LARGE_FP16",
"default": true,
"preload": false
}
}
}
}知っておきたい選択がいくつかあります。
preload: false— モデルは起動時ではなく、初回利用時に読み込まれます。bun run devの起動を速く保ちます。ctx_size: 4096— チャットモデルのコンテキストウィンドウ。あとで 検索の top-K を上げる場合、この数字を意識してください。temp: 0.2— 引用根拠付きの回答に向けた低温度設定。モデルにはソースを 言い換えてほしいので、創作させない方向です。
8. ソース用の場所を作る
mkdir src tests examplesこれ以降の各ウォークスルーステップは src/ 配下にファイルを書き込みます。
tests/ には rag.ts と files.ts 用に追加する Bun テスト 2 本が入ります。
examples/sample-brain/ は CLI が向けるデモフォルダです。
現時点の状態
プロジェクトの骨組みはこれで揃いました。package.json、
tsconfig.json、biome.json、qvac.config.json、そして 3 つの空の
ディレクトリ (src/、tests/、examples/) です。bun run typecheck
はまだ実行しないでください。include: ["src/**/*.ts", "tests/**/*.ts"]
の設定で両ディレクトリが空の状態だと、TypeScript は次のエラーで
終了します。
error TS18003: No inputs were found in config file 'tsconfig.json'.これは現時点では想定どおりです。最初のソースファイルは次のステップ
で登場します。src/domain.ts が出来た瞬間に bun run typecheck は
通るようになり、ウォークスルーの残りの間はずっとパスし続けます。
`bun init` が用意しないもの
bun init -y は意図的に最小限です。Biome、QVAC、strict TypeScript の
フラグ、上記のスクリプトセットは入りません。本ページは bun init の
上に乗せる「こだわり層」と捉えてください。これ以降はすべて、この 8
ステップの結果のような状態のプロジェクトを前提にしています。
次はドメイン型と AppError、最初の
本物のソースファイルです。