Skip to main content
This tutorial extends Getting started into a project you can build on. By the end you will have a structured folder layout with a tsup build pipeline, a .env file, a first knowledge context registered on the app, and both processes running locally.

Prerequisites

  • Completed Setup@exulu/backend installed, Node.js 22.18.0.
  • Completed Getting started — you have src/exulu.ts, src/server.ts, and src/worker.ts in some form.
  • A running Postgres instance and a running Redis instance (see Self-hosting quickstart if you need them locally).

What you will build

A project structured exactly as IMP expects in production: two separate entry points (server and worker), a shared app-initialization module, a first ExuluContext for a generic knowledge collection, and scripts that match the container split used in deployment.
1

Organize the folder layout

The recommended layout mirrors the production container split:
Create the src/contexts directory:
2

Configure tsup

tsup compiles TypeScript into two separate output bundles — one for the server and one for the worker — that Node.js can run directly:
tsup.config.ts
Both entries share the same src/exulu.ts module at build time. tsup bundles each entry independently, so the server bundle and the worker bundle are separate files with no runtime coupling.
3

Add package.json scripts

package.json
dev:server and dev:worker use tsx watch for fast iteration — file changes restart the process automatically. start:server and start:worker run the compiled output for production.
4

Create the .env file

.env
@exulu/backend auto-loads this file via a dotenv/config import it prepends to every bundle — you do not need to call dotenv yourself.
Never commit .env to version control. Add it to .gitignore immediately.
5

Define a first context

Create src/contexts/index.ts with a simple knowledge context:
src/contexts/index.ts
This context has no data source yet — you will add items manually through the IMP UI or programmatically via createItem(). See Defining contexts for a full context with sources and embedder queues.
6

Wire everything in exulu.ts

src/exulu.ts
requireSystemDependencies: false lets the server start even if pandoc or soffice are not installed locally. Remove this flag in production or when you need document processing.
7

Write server.ts and worker.ts

src/server.ts
src/worker.ts
Both files import ready (the unresolved promise) and await it independently. app.express.init() registers routes and starts the LiteLLM proxy supervisor when EXULU_USE_LITELLM=true. app.bullmq.workers.create() connects to Redis and starts consuming all registered queues.
8

Run the project

Open two terminals.Terminal 1 — server:
On the very first boot you will see:
Copy the API key immediately — IMP logs a new key on every startup but only persists the first one. Keys logged on later restarts do not work.
Terminal 2 — worker:
The worker connects to Redis and starts processing jobs. With team_knowledge registered, it will embed any items you add to the context.

What you built

  • A tsup project with separate server and worker entry points.
  • A .env-driven configuration that the package loads automatically.
  • A first ExuluContext (team_knowledge) registered on the app, ready to store items and generate embeddings on insert.
  • Two development scripts that hot-reload on file change.

Next steps

Defining contexts

Add fields, sources, and embedder queues to build production-ready contexts.

Data sources and sync

Pull data from an external API on a cron schedule.

Queues and workers

Register BullMQ queues and scope your worker process.

Custom tools

Give agents callable functions backed by your own code.