LocalLens
Walkthrough

0. Setup do projeto

Inicialize um projeto Bun + TypeScript, instale o QVAC e fixe as dev tools que você vai usar pelo resto do walkthrough.

Antes de qualquer arquivo fonte existir, você precisa de um projeto Bun + TypeScript funcionando. Esse passo leva um minuto e produz a forma que o src/cli.ts e o src/server.ts futuros vão rodar por dentro.

Pré-requisitos

  • Bun >=1.3.0 (install)
  • Node >=22.17.0 (usado pelo TypeScript e alguns módulos node:)

Sem chave da OpenAI. Sem conta no Pinecone. Sem GPU. Tudo roda localmente através do QVAC.

1. Criar o projeto

mkdir locallens
cd locallens
bun init -y

bun init -y escreve um package.json, tsconfig.json, .gitignore mínimos, e um index.ts placeholder. Apaga o index.ts — os pontos de entrada reais (src/cli.ts, src/server.ts) vêm depois.

2. Instalar dependências

bun add @qvac/sdk
bun add -d typescript @types/bun @biomejs/biome

Para que serve cada um:

PacotePorquê
@qvac/sdkO loop de IA local: carregamento de modelo, RAG, completion. A única dependência de runtime que o LocalLens tem.
typescriptTipos estritos para os oito arquivos que você vai escrever.
@types/bunDefinições de tipo para Bun.argv, Bun.serve, Bun.file, import.meta.dir.
@biomejs/biomeUma ferramenta para lint e format. Substitui ESLint + Prettier.

Essa é a superfície de dependência inteira. Sem banco vetorial, sem biblioteca de embedding, sem chunker.

3. Fixar as versões de runtime

Abre o package.json recém-criado e coloca type: "module" mais o campo engines, para que qualquer um clonando o repositório pegue o mesmo runtime:

package.json
{
  "name": "locallens",
  "version": "0.1.0",
  "type": "module",
  "private": true,
  "license": "MIT",
  "engines": {
    "bun": ">=1.3.0",
    "node": ">=22.17.0"
  }
}

4. Adicionar os scripts que você vai usar

Adiciona estes ao package.json. Cada um é conectado por um passo seguinte. Por enquanto só precisam existir:

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 é o comando composto que o CI usa. Roda lint → types → tests → build, nessa ordem, e sai com código não-zero se qualquer passo falhar.

5. Apertar o tsconfig.json

bun init produz um default razoável. O walkthrough quer uns extras: modo estrito, tipos do Bun, e a capacidade de importar com extensões .ts explícitas. Substitui o arquivo gerado por este:

tsconfig.json
{
  "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"]
}

Duas flags que vale apontar:

  • allowImportingTsExtensions: true deixa você escrever import "./domain.ts" em arquivos fonte. O Bun roda direto; a extensão explícita mantém o tsc feliz.
  • verbatimModuleSyntax: true exige import type para imports só de tipo. O código do walkthrough é escrito assim. Essa flag impõe isso.

6. Configurar o Biome

O Biome cuida de lint e format. Um arquivo de config:

biome.json
{
  "$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"
    }
  }
}

A exclusão !.locallens importa quando o app está rodando. Essa pasta é onde o JSON store e os dados dos brains vivem, e o Biome não deve tentar formatar.

7. Configurar o QVAC

O QVAC lê o config de runtime de qvac.config.json na raiz do repositório. Cria agora para o gateway ter o que carregar:

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
      }
    }
  }
}

Algumas escolhas que vale conhecer:

  • preload: false — modelos carregam no primeiro uso, não no boot. Mantém o bun run dev responsivo.
  • ctx_size: 4096 — a janela de contexto do modelo de chat. Se você aumentar o top-K na recuperação depois, deixa isso à vista.
  • temp: 0.2 — temperatura baixa para respostas embasadas em citações. O modelo deve reformular a fonte, não inventar.

8. Fazer um lugar para o código

mkdir src tests examples

Todo passo do walkthrough daqui em diante escreve um arquivo em src/. tests/ vai guardar os dois testes Bun que você vai adicionar para rag.ts e files.ts. examples/sample-brain/ é a pasta demo que a CLI aponta.

Onde você está

O esqueleto do projeto está pronto: package.json, tsconfig.json, biome.json, qvac.config.json, e três pastas vazias (src/, tests/, examples/). Não rode bun run typecheck ainda — com include: ["src/**/*.ts", "tests/**/*.ts"] e nada dentro de nenhuma das duas pastas, o TypeScript sai com:

error TS18003: No inputs were found in config file 'tsconfig.json'.

Isso é esperado nesse momento. O primeiro arquivo fonte aparece no próximo passo. Assim que src/domain.ts existir, bun run typecheck fica verde e continua verde pelo resto do walkthrough.

O que o `bun init` não te dá

bun init -y é minimal de propósito. Não adiciona Biome, QVAC, flags estritas de TypeScript, ou o conjunto de scripts acima. Trata essa página como a camada opinada que você parafusa em cima do bun init. Tudo daqui em diante assume que o projeto se parece com o resultado desses oito passos.

A seguir: tipos de domínio e AppError, o primeiro arquivo fonte de verdade.

On this page