- Node.js >=20.0.0 (see root
package.jsonengines.node) - pnpm 9.15.0 (see root
packageManager) - Docker Engine 24+ with the Compose v2 plugin
Recommended editor extensions: ESLint, Prettier.
Verify the toolchain in one pass:
pnpm install && pnpm types:check && pnpm lintdocker compose up -dcp .env.example .env- Set at minimum:
OPENAI_API_KEY, absoluteAURIS_DATA_PATHpointing atpackages/workers/seeds/inbox,AURIS_CHROMA_URL=http://127.0.0.1:8000, andELASTICSEARCH_URL=http://127.0.0.1:9200whenAURIS_SPARSE_SEARCHuses Elasticsearch. pnpm dev— boots Express onPORT(defaults to 3000) with file watching viatsx.pnpm data:seed— scansAURIS_DATA_PATHfor files matchingDATA_SOURCEextensions, streams documents, and runsindexRawDocumentswith hash-based skips.- Confirm retrieval:
curl -s -X POST http://127.0.0.1:3000/v1/query \
-H 'content-type: application/json' \
-d '{"query":"What soil pH does watermelon prefer?"}'Expect JSON shaped like { "answer": string, "citations": [...], "confidence": number, "traceId": string, "pipeline": { ... } }.
pnpm test— runs Vitest unit suites (pure functions, pipelines, and adapters with mocks).pnpm test:integration— runs the Vitest config reserved for*.integration.test.tsfiles (currently none; exits successfully withpassWithNoTests).pnpm docker:up && pnpm dev(in a second terminal) thencurl -s http://127.0.0.1:3000/v1/health— manual smoke against real containers until automated API integration tests are added.
Evaluation package:
pnpm --filter @auris/evaluation run eval:goldenCompiles the evaluation package, loads evaluation/golden/golden-set.json from the repository root (override with GOLDEN_SET_PATH), and prints a short JSON summary.
| Script | What it does | When to use it |
|---|---|---|
pnpm dev |
API watch mode (@auris/api) |
Daily backend work |
pnpm dev:workers |
Workers package CLI in dev mode | Worker-only changes |
pnpm build |
tsc build for every workspace package |
Before release or Docker-less runs |
pnpm build:api |
Build @auris/api only |
Narrow API compile check |
pnpm types:check |
tsc --noEmit in all packages |
CI and pre-push |
pnpm lint |
ESLint across packages | Style and correctness gate |
pnpm lint:fix |
ESLint with --fix |
Auto-fix safe violations |
pnpm fmt:write |
Prettier write for the repo | Format everything |
pnpm fmt:check |
Prettier check (no writes) | CI formatting gate |
pnpm test |
Vitest run once | Default test entry |
pnpm test:watch |
Vitest watch | Tight feedback loop |
pnpm test:coverage |
Vitest with coverage thresholds | Before merging risky changes |
pnpm docker:up |
docker compose up -d |
Start Chroma and Elasticsearch |
pnpm docker:down |
docker compose down |
Stop containers |
pnpm docker:down:volumes |
docker compose down -v |
Wipe named volumes |
pnpm docker:logs |
Follow all Compose logs | Debugging services |
pnpm docker:logs:chroma |
Follow Chroma logs | Vector-store issues |
pnpm docker:logs:search |
Follow Elasticsearch logs | Sparse-index issues |
pnpm docker:ps |
docker compose ps |
Check container state |
pnpm docker:restart |
Restart every Compose service | Recover stuck deps |
pnpm docker:restart:chroma |
Restart Chroma only | Targeted vector recycle |
pnpm docker:restart:search |
Restart Elasticsearch only | Targeted sparse recycle |
pnpm docker:pull |
Pull Compose images | Refresh base images |
pnpm docker:build |
docker compose build |
Rebuild the optional API image |
pnpm docker:reset |
down -v then up |
Clean slate for local data |
pnpm data:seed |
Build shared then run the indexing worker | After .env changes |
pnpm data:seed:dry-run |
Same as seed with --dry-run |
Count documents without writing |
pnpm repo:clean |
Remove package dist/ folders and root node_modules |
Nuclear local reset |
pnpm repo:setup |
install + docker:up + types:check |
Fresh clone bootstrap |
pnpm api:health |
curl + jq against /v1/health |
Quick API readiness (needs curl and jq) |
Workspace packages expose build:tsc, types:check, lint:check, lint:fix, and clean:dist (plus package-specific scripts such as dev:watch on @auris/api). Run them with pnpm --filter <name> run <script>.
Concrete walkthrough: adding an Acme LLM provider.
-
Locate
LLMProviderinpackages/core/src/ports/llm-provider.tsand copy the interface into your editor while implementing the adapter. -
Create
packages/infra/src/llm/acme-llm-provider.tswith a class that implements the interface (mirrorOpenAiLlmProvider).
import type {
ChatMessage,
CompletionOptions,
CompletionResult,
LLMProvider,
PipelineContext,
} from "@auris/core";
export class AcmeLlmProvider implements LLMProvider {
readonly modelId = "acme-turbo";
constructor(private readonly apiKey: string) {}
async complete(
messages: readonly ChatMessage[],
options: CompletionOptions,
ctx: PipelineContext,
): Promise<CompletionResult> {
void messages;
void options;
void ctx;
void this.apiKey;
return {
text: "pong",
promptTokens: 1,
completionTokens: 1,
model: this.modelId,
};
}
}- Register the adapter inside
createLlminpackages/infra/src/wiring/composition.tsby importingAcmeLlmProviderand inserting a branch before the existinggpt_4ohandling.
import { AcmeLlmProvider } from "../llm/acme-llm-provider.js";
if (config.providers.llm === "acme_turbo") {
return new AcmeLlmProvider(config.acmeApiKey ?? "");
}-
Extend
packages/shared/src/config/schema.tswith any new secrets or enums (for example add"acme_turbo"to theproviders.llmenum andacmeApiKey: z.string().optional()onappConfigSchema), then map them throughpackages/shared/src/config/load-config.tswithenvString("ACME_API_KEY"). -
Add
packages/infra/src/llm/acme-llm-provider.test.ts.
import { describe, it, expect } from "vitest";
import { StubLlmProvider } from "./stub-llm-provider.js";
describe("LLM provider harness", () => {
it("documents the reject path for unconfigured models", async () => {
const llm = new StubLlmProvider("gpt-4o");
await expect(llm.complete([], { maxOutputTokens: 8 }, { traceId: "t" })).rejects.toThrow(
/not configured/,
);
});
});Swap StubLlmProvider for AcmeLlmProvider once your HTTP client is mockable.
-
Implement the
DataSourceProviderport frompackages/core/src/data-sources/DataSourceProvider.ts(seeLocalFilesDataSourceProviderunderpackages/infra/src/data-sources/local-files/for a filesystem example). -
Register the provider inside
resolveDataSourceProviderinpackages/infra/src/data-sources/registry.ts, wiring any new configuration throughpackages/shared/src/config/schema.tsandpackages/shared/src/config/load-config.ts. -
Add focused unit tests next to the adapter and extend
packages/infra/src/data-sources/registry.test.tswhen registration rules change. -
Document required environment variables beside the adapter and update
.env.examplewhen new secrets or paths are introduced.
Conventional Commits.
| Type | When to use | Example |
|---|---|---|
feat |
User-visible capability | feat: add catalog feed data source |
fix |
Bug fix | fix: guard empty sparse responses |
docs |
Documentation only | docs: expand architecture overview |
refactor |
Internal change, same behavior | refactor: extract tracing helpers |
test |
Tests only | test: cover rrf tie handling |
chore |
Tooling or maintenance | chore: bump vitest |
perf |
Measurable speedup | perf: batch embedding calls |
- Linked issue or rationale is described in the PR body.
-
pnpm lintpasses locally. -
pnpm types:checkpasses locally. -
pnpm testpasses locally. - New adapters include README notes for required environment variables.
- Configuration changes update
config/default.yaml,.env.example, or both. - Sensitive values never appear in commits or logs.
- Documentation reflects behavior changes in
README.mdorARCHITECTURE.md.