LocalLens
Walkthrough

0. Setup del proyecto

Inicializa un proyecto Bun + TypeScript, instala QVAC y fija las dev tools que vas a usar el resto del walkthrough.

Antes de que exista cualquier archivo fuente, necesitas un proyecto Bun + TypeScript funcionando. Este paso toma alrededor de un minuto y produce la forma dentro de la cual van a correr después src/cli.ts y src/server.ts.

Prerrequisitos

  • Bun >=1.3.0 (instalación)
  • Node >=22.17.0 (usado por TypeScript y algunos módulos node:)

Sin key de OpenAI. Sin cuenta de Pinecone. Sin GPU. Todo corre localmente a través de QVAC.

1. Crea el proyecto

mkdir locallens
cd locallens
bun init -y

bun init -y escribe un package.json mínimo, un tsconfig.json, un .gitignore y un index.ts placeholder. Borra index.ts — los puntos de entrada reales (src/cli.ts, src/server.ts) vienen después.

2. Instala dependencias

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

Para qué es cada una:

PaquetePor qué
@qvac/sdkEl loop de IA local: carga de modelos, RAG, completion. La única dependencia de runtime que LocalLens tiene.
typescriptTipos estrictos para los ocho archivos que estás por escribir.
@types/bunDefiniciones de tipos para Bun.argv, Bun.serve, Bun.file, import.meta.dir.
@biomejs/biomeUna sola herramienta para linting y formato. Reemplaza ESLint + Prettier.

Esa es toda la superficie de dependencias. Sin base de datos vectorial, sin librería de embeddings, sin chunker.

3. Fija las versiones del runtime

Abre el package.json recién creado y pon type: "module" más el campo engines, así cualquiera que clone el repo tiene el mismo 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. Agrega los scripts que vas a usar

Agrega esto a package.json. Cada uno queda conectado por un paso posterior. Por ahora solo necesitan 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 es el comando compuesto que usa CI. Corre lint → tipos → tests → build, en ese orden, y sale con código distinto de cero si algún paso falla.

5. Aprieta tsconfig.json

bun init produce un default razonable. El walkthrough quiere algunos extras: strict mode, tipos de Bun y la habilidad de importar extensiones .ts explícitamente. Reemplaza el archivo generado con esto:

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

Dos flags que vale la pena marcar:

  • allowImportingTsExtensions: true te deja escribir import "./domain.ts" en archivos fuente. Bun los corre directamente; la extensión explícita mantiene a tsc contento.
  • verbatimModuleSyntax: true requiere import type para imports solo de tipos. El código del walkthrough está escrito así. Este flag lo impone.

6. Configura Biome

Biome maneja linting y formato. Un solo archivo 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"
    }
  }
}

La exclusión !.locallens importa una vez que la app está corriendo. Esa carpeta es donde viven el store JSON y los datos del cerebro, y Biome no debería intentar formatearla.

7. Configura QVAC

QVAC lee su config de runtime desde qvac.config.json en la raíz del repo. Créalo ahora para que el gateway tenga algo contra qué cargar:

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

Algunas decisiones que vale la pena conocer:

  • preload: false — los modelos cargan en el primer uso, no en el boot. Mantiene bun run dev ágil.
  • ctx_size: 4096 — la ventana de contexto del modelo de chat. Si subes el top-K en recuperación más adelante, mantén esto en la mira.
  • temp: 0.2 — temperatura baja para respuestas fundamentadas en citas. El modelo debe reformular la fuente, no inventar.

8. Haz lugar para el código fuente

mkdir src tests examples

Cada paso del walkthrough de acá en adelante escribe un archivo en src/. tests/ va a tener los dos tests de Bun que vas a agregar para rag.ts y files.ts. examples/sample-brain/ es la carpeta demo a la que apunta la CLI.

Dónde estás

El esqueleto del proyecto está listo: package.json, tsconfig.json, biome.json, qvac.config.json, y tres carpetas vacías (src/, tests/, examples/). No corras bun run typecheck todavía — con include: ["src/**/*.ts", "tests/**/*.ts"] y nada dentro de ninguna de las dos carpetas, TypeScript termina con:

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

Eso es lo esperado en este punto. El primer archivo fuente aterriza en el siguiente paso. En cuanto src/domain.ts exista, bun run typecheck se pone en verde y se queda así por el resto del walkthrough.

Lo que `bun init` no te da

bun init -y es intencionalmente mínimo. No agrega Biome, QVAC, flags estrictos de TypeScript, ni el set de scripts de arriba. Trata esta página como la capa opinada que le pones encima a bun init. Todo de acá en adelante asume que el proyecto se ve como el resultado de estos ocho pasos.

Lo que sigue: tipos de dominio y AppError, el primer archivo fuente real.

On this page