Flow
ServicesIntelligence Service

Getting started

Run intelligence locally with fake models, watch a conversation turn into a claim, and swap in a real embedding provider.

Prerequisites

Follow Local development, then:

./localenv up intelligence-api

Postgres has to have the vector extension available, which is why docker-compose.yml uses the pgvector image (ADR 0022). ./localenv takes care of that. Your own Postgres on port 5433 will fail the first migration.

It runs without any credentials

EMBEDDING_PROVIDER and EXTRACTION_PROVIDER default to fakes. The fake embedder returns the same vector for the same text every time, and the fake extractor proposes no claims at all. So a fresh checkout starts, migrates, and answers requests. Search returns results. They just do not mean anything.

curl -s 'localhost:8108/v1/knowledge/search?q=pricing+tiers' \
  -H 'X-Dev-Principal: [email protected]' | jq

A program can call with a broker credential instead of an Access token. The JWT's email is the caller, the same address an Access session would use. See docs/decisions/0079-a-person-mints-their-own-api-credential.md.

Locally, DEV_AUTH=1 takes the caller's identity from the X-Dev-Principal header. The default is [email protected]. Set DEV_ACTOR in the repo-root .env to use a different address; the local stack also puts that person on INTELLIGENCE_REVIEWERS, so you can try the review flow. There is no list of who may read: knowledge belongs to the whole company, so anyone the gateway lets in can read it.

Watch a conversation turn into a claim

The whole path needs workspace and the workers:

./localenv up workspace-api intelligence-api intelligence-listener intelligence-enrichment

Say something worth reading

Add a turn in workspace (see its getting started). The listener queues one observe job and waits before running it. An active conversation costs one job, not one per message, so expect a pause rather than an instant result.

Watch the queue

The Enrichment queue: The Postgres table intelligence's derivation work runs through: leased claims, deduplication on job and target, exponential backoff, and a dead letter. It is a table rather than a broker queue because a burst of turns in one conversation has to collapse into one extraction, which is a row update. is a Postgres table, so you can query it directly. GET /internal/jobs/depth reports the same thing:

curl -s localhost:8108/internal/jobs/depth \
  -H 'Authorization: Bearer local-scheduler-token-not-a-secret-0' | jq

Read what came out

curl -s 'localhost:8108/v1/knowledge/insights' -H 'X-Dev-Principal: [email protected]' | jq
curl -s 'localhost:8108/v1/knowledge/candidates' -H 'X-Dev-Principal: [email protected]' | jq

With the fake extractor both lists are empty, which is the honest answer: nothing proposed a claim. Point the EXTRACTION_* settings at a real model to see the pipeline produce something.

Point it at a real provider

Set these in services/intelligence/.env. They are the same variables the deployment uses, which is the reason the model calls live in the service instead of in every client:

EMBEDDING_PROVIDER=openai
EMBEDDING_BASE_URL=…
EMBEDDING_API_KEY=…
EMBEDDING_MODEL=text-embedding-3-small
EMBEDDING_DIMENSIONS=1536

openai here names the request format, not the company. Azure OpenAI, OpenAI, Together, vLLM, LocalAI, and Ollama's compatibility endpoint all accept it.

EMBEDDING_DIMENSIONS is fixed by the first migration, because vector(N) is a column type. Changing the model or the width means recalculating every embedding, not editing a variable. Locally, drop the database. Deployed, that is the reindex job.

Every key is documented in services/intelligence/.env.example.

Run the batch jobs by hand

The scheduled work is plain HTTP, so you do not need a scheduler locally:

curl -s -X POST localhost:8108/internal/jobs/cluster-links \
  -H 'Authorization: Bearer local-scheduler-token-not-a-secret-0'

That call only queues the job and returns. ./localenv up intelligence-batch is what actually runs it.

Review console

The review UI is intelligence-app on localhost:3503:

./localenv up intelligence-app

The hamburger drawer is three collapsible sections, the same shape as tool-app: Workspace, Intelligence, and Admin. Admin items, and Facts, are hidden unless the caller is a platform admin. The icon ribbon stays a flat list of every page.

Safari and Chrome can install it on the home screen. The icon and splash screens live under frontend/intelligence-app/public/image/pwa.

Tests

go test ./services/intelligence/...

On this page