Tools
Tools: Prompt management, RAG, and agents with HazelJS
2026-03-08
0 views
admin
Introduction ## What’s in the box ## Quick start ## Prompts API: live registry management ## RAG API: registry-driven Q&A ## Agent API: supervisor and workers from the registry ## AI Tasks API: four registry-backed tasks ## Prompt keys reference ## Architecture ## Environment and production notes ## Summary One starter: typed prompt templates, a live registry, FileStore persistence, RAG, supervisor agents, and AI tasks—all driven by the same prompt system Managing LLM prompts well is hard: you want versioning, overrides without redeploys, and a single place that RAG, agents, and plain AI tasks all read from. The HazelJS Prompt Starter shows how to do exactly that. Built on HazelJS, @hazeljs/prompts, @hazeljs/rag, and @hazeljs/agent, it gives you a PromptRegistry with typed templates, FileStore persistence, and a REST API to inspect and override any prompt at runtime. RAG answer synthesis, the supervisor agent, worker agents, and four AI tasks (welcome, summarize, sentiment, translate) all use that same registry. In this post we walk through what’s in the starter and how to use it. One server, one registry: change a prompt with PUT /api/prompts/:key, and the next RAG question, agent run, or AI task uses the new template. Server runs at http://localhost:3000. Try listing prompts: Then override the RAG answer prompt and ask a question (see examples below). Every prompt is identified by a key (e.g. rag:answer, agent:supervisor:system, app:summarize). The REST API lets you manage them without touching code. Example: override the RAG answer prompt Example: preview a prompt with variables The RAG pipeline uses the rag:answer prompt from the registry. Override it via the Prompts API and the next /api/rag/ask call uses the new template. Workflow: Override rag:answer with PUT /api/prompts/rag%3Aanswer, then run the same question again — the answer style follows the new prompt. The supervisor and worker agents read their prompts from the registry. Override agent:supervisor:system, agent:supervisor:routing, agent:worker:researcher, or agent:worker:analyst to change behaviour without redeploying. The response includes supervisorSystemPrompt — the exact prompt used for the supervisor. Override agent:supervisor:system or agent:worker:researcher and run again to see different delegation and output styles. Four built-in AI tasks (welcome, summarize, sentiment, translate) use app prompts from the registry. Templates and sample variables are visible via the API. RAG, agent, and AI services all use the global PromptRegistry; they never hold prompt strings themselves. PromptsService configures the FileStore and registers app-specific keys at startup; overrides are persisted and survive restarts. Key env vars: OPENAI_API_KEY (required), EMBEDDING_MODEL, QA_MODEL, AGENT_MODEL, PROMPTS_FILE (default ./data/prompts.json), PORT. See the starter’s .env.example and README for the full list. For production you can swap the FileStore for a RedisStore (or another backend) by changing the registry configuration in PromptsService; the REST API and all consumers stay the same. The HazelJS Prompt Starter gives you: Clone it, set OPENAI_API_KEY, and you have a single app that demonstrates prompt management, RAG, supervisor agents, and AI tasks in one place. For more on HazelJS and @hazeljs/prompts, see hazeljs.com and the HazelJS repository. Templates let you quickly answer FAQs or store snippets for re-use. Prompt management is the underappreciated piece of this stack. RAG solves retrieval, agents solve orchestration, but the actual prompt structure — who the model is, what it's allowed to do, how it should format output — is usually a scattered afterthought. Treating each semantic piece (role, constraints, output format) as a distinct managed block rather than one giant string makes iteration and reuse much cleaner. flompt.dev / github.com/Nyrok/flompt Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse COMMAND_BLOCK:
git clone https://github.com/hazel-js/hazeljs-prompt-starter.git
cd hazeljs-prompt-starter
cp .env.example .env # add OPENAI_API_KEY
npm install
npm run dev Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
git clone https://github.com/hazel-js/hazeljs-prompt-starter.git
cd hazeljs-prompt-starter
cp .env.example .env # add OPENAI_API_KEY
npm install
npm run dev COMMAND_BLOCK:
git clone https://github.com/hazel-js/hazeljs-prompt-starter.git
cd hazeljs-prompt-starter
cp .env.example .env # add OPENAI_API_KEY
npm install
npm run dev COMMAND_BLOCK:
curl http://localhost:3000/api/prompts Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl http://localhost:3000/api/prompts COMMAND_BLOCK:
curl http://localhost:3000/api/prompts COMMAND_BLOCK:
curl -X PUT http://localhost:3000/api/prompts/rag%3Aanswer \ -H "Content-Type: application/json" \ -d '{ "template": "Answer in one sentence.\nContext: {context}\nQuestion: {query}\nAnswer:", "metadata": { "version": "2.0.0", "description": "Concise one-sentence answers" } }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X PUT http://localhost:3000/api/prompts/rag%3Aanswer \ -H "Content-Type: application/json" \ -d '{ "template": "Answer in one sentence.\nContext: {context}\nQuestion: {query}\nAnswer:", "metadata": { "version": "2.0.0", "description": "Concise one-sentence answers" } }' COMMAND_BLOCK:
curl -X PUT http://localhost:3000/api/prompts/rag%3Aanswer \ -H "Content-Type: application/json" \ -d '{ "template": "Answer in one sentence.\nContext: {context}\nQuestion: {query}\nAnswer:", "metadata": { "version": "2.0.0", "description": "Concise one-sentence answers" } }' COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/prompts/app%3Asummarize/preview \ -H "Content-Type: application/json" \ -d '{ "variables": { "text": "HazelJS is a TypeScript framework.", "maxWords": "10" } }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/prompts/app%3Asummarize/preview \ -H "Content-Type: application/json" \ -d '{ "variables": { "text": "HazelJS is a TypeScript framework.", "maxWords": "10" } }' COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/prompts/app%3Asummarize/preview \ -H "Content-Type: application/json" \ -d '{ "variables": { "text": "HazelJS is a TypeScript framework.", "maxWords": "10" } }' COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/rag/ingest \ -H "Content-Type: application/json" \ -d '{ "documents": [ { "content": "HazelJS is a TypeScript backend framework built for scalability.", "source": "intro.txt" }, { "content": "The @hazeljs/prompts package provides typed, overridable prompt templates.", "source": "prompts.txt" } ] }' curl -X POST http://localhost:3000/api/rag/ask \ -H "Content-Type: application/json" \ -d '{ "question": "What is HazelJS?" }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/rag/ingest \ -H "Content-Type: application/json" \ -d '{ "documents": [ { "content": "HazelJS is a TypeScript backend framework built for scalability.", "source": "intro.txt" }, { "content": "The @hazeljs/prompts package provides typed, overridable prompt templates.", "source": "prompts.txt" } ] }' curl -X POST http://localhost:3000/api/rag/ask \ -H "Content-Type: application/json" \ -d '{ "question": "What is HazelJS?" }' COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/rag/ingest \ -H "Content-Type: application/json" \ -d '{ "documents": [ { "content": "HazelJS is a TypeScript backend framework built for scalability.", "source": "intro.txt" }, { "content": "The @hazeljs/prompts package provides typed, overridable prompt templates.", "source": "prompts.txt" } ] }' curl -X POST http://localhost:3000/api/rag/ask \ -H "Content-Type: application/json" \ -d '{ "question": "What is HazelJS?" }' COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/agent/run \ -H "Content-Type: application/json" \ -d '{ "task": "Research the benefits of RAG over fine-tuning and analyse the trade-offs." }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/agent/run \ -H "Content-Type: application/json" \ -d '{ "task": "Research the benefits of RAG over fine-tuning and analyse the trade-offs." }' COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/agent/run \ -H "Content-Type: application/json" \ -d '{ "task": "Research the benefits of RAG over fine-tuning and analyse the trade-offs." }' COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/ai/task/welcome \ -H "Content-Type: application/json" \ -d '{ "name": "Alice", "topic": "prompt engineering" }' curl -X POST http://localhost:3000/api/ai/task/summarize \ -H "Content-Type: application/json" \ -d '{ "text": "HazelJS is a modular TypeScript framework...", "maxWords": "30" }' curl -X POST http://localhost:3000/api/ai/task/sentiment \ -H "Content-Type: application/json" \ -d '{ "text": "I love how easy HazelJS makes dependency injection!" }' Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/ai/task/welcome \ -H "Content-Type: application/json" \ -d '{ "name": "Alice", "topic": "prompt engineering" }' curl -X POST http://localhost:3000/api/ai/task/summarize \ -H "Content-Type: application/json" \ -d '{ "text": "HazelJS is a modular TypeScript framework...", "maxWords": "30" }' curl -X POST http://localhost:3000/api/ai/task/sentiment \ -H "Content-Type: application/json" \ -d '{ "text": "I love how easy HazelJS makes dependency injection!" }' COMMAND_BLOCK:
curl -X POST http://localhost:3000/api/ai/task/welcome \ -H "Content-Type: application/json" \ -d '{ "name": "Alice", "topic": "prompt engineering" }' curl -X POST http://localhost:3000/api/ai/task/summarize \ -H "Content-Type: application/json" \ -d '{ "text": "HazelJS is a modular TypeScript framework...", "maxWords": "30" }' curl -X POST http://localhost:3000/api/ai/task/sentiment \ -H "Content-Type: application/json" \ -d '{ "text": "I love how easy HazelJS makes dependency injection!" }' COMMAND_BLOCK:
src/
├── main.ts # Bootstrap + startup banner
├── app.module.ts # Root HazelModule
├── prompts/ # @hazeljs/prompts integration
│ ├── prompts.service.ts # FileStore, app prompt registration
│ ├── prompts.controller.ts # REST API for the registry
│ └── prompts.module.ts
├── rag/ # @hazeljs/rag — reads rag:answer from registry
│ ├── rag.service.ts
│ ├── rag.controller.ts
│ └── rag.module.ts
├── agent/ # @hazeljs/agent — supervisor + workers from registry
│ ├── agent.service.ts
│ ├── agent.controller.ts
│ ├── workers/researcher.agent.ts
│ ├── workers/analyst.agent.ts
│ └── agent.module.ts
├── ai/ # AI tasks via registry prompts
│ ├── ai-task.service.ts
│ ├── ai-task.controller.ts
│ └── ai.module.ts
├── llm/ # OpenAI LLM provider for agents
│ └── openai-llm.provider.ts
└── health/ └── health.controller.ts # Liveness + readiness Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
src/
├── main.ts # Bootstrap + startup banner
├── app.module.ts # Root HazelModule
├── prompts/ # @hazeljs/prompts integration
│ ├── prompts.service.ts # FileStore, app prompt registration
│ ├── prompts.controller.ts # REST API for the registry
│ └── prompts.module.ts
├── rag/ # @hazeljs/rag — reads rag:answer from registry
│ ├── rag.service.ts
│ ├── rag.controller.ts
│ └── rag.module.ts
├── agent/ # @hazeljs/agent — supervisor + workers from registry
│ ├── agent.service.ts
│ ├── agent.controller.ts
│ ├── workers/researcher.agent.ts
│ ├── workers/analyst.agent.ts
│ └── agent.module.ts
├── ai/ # AI tasks via registry prompts
│ ├── ai-task.service.ts
│ ├── ai-task.controller.ts
│ └── ai.module.ts
├── llm/ # OpenAI LLM provider for agents
│ └── openai-llm.provider.ts
└── health/ └── health.controller.ts # Liveness + readiness COMMAND_BLOCK:
src/
├── main.ts # Bootstrap + startup banner
├── app.module.ts # Root HazelModule
├── prompts/ # @hazeljs/prompts integration
│ ├── prompts.service.ts # FileStore, app prompt registration
│ ├── prompts.controller.ts # REST API for the registry
│ └── prompts.module.ts
├── rag/ # @hazeljs/rag — reads rag:answer from registry
│ ├── rag.service.ts
│ ├── rag.controller.ts
│ └── rag.module.ts
├── agent/ # @hazeljs/agent — supervisor + workers from registry
│ ├── agent.service.ts
│ ├── agent.controller.ts
│ ├── workers/researcher.agent.ts
│ ├── workers/analyst.agent.ts
│ └── agent.module.ts
├── ai/ # AI tasks via registry prompts
│ ├── ai-task.service.ts
│ ├── ai-task.controller.ts
│ └── ai.module.ts
├── llm/ # OpenAI LLM provider for agents
│ └── openai-llm.provider.ts
└── health/ └── health.controller.ts # Liveness + readiness - One registry — PromptTemplate, PromptRegistry, and FileStore for typed, overridable prompts that persist across restarts.
- One REST API — List, preview, and override any prompt at runtime; RAG, agents, and AI tasks pick up changes immediately.
- RAG, agents, and AI tasks — All reading from the same registry so you can tune behaviour without code changes. - Joined Sep 25, 2025
how-totutorialguidedev.toaiopenaillmserverroutinggitgithub