Provider-neutral JavaScript/TypeScript SDK packages for AI applications, with a browser Studio web component, Fetch-compatible backend routes, Ollama provider support, optional SQLite memory, PostgreSQL RAG, and a backend-first security boundary.
Documentation & Live Demos | npm | Issues | Repository | Community Discussions
Latest tested package releases: core family 0.0.3, UI 0.0.5
Credits: Stackline AI package architecture, publishing, and documentation by Alexandro Paixao Marques.
Stackline AI exists to make AI applications installable without hiding the important production boundaries. The browser gets a reusable Studio UI, but providers, API keys, Ollama targets, SQL, RAG filters, and memory paths stay behind a backend route.
The package family is split by responsibility so a user can install only the layer they need: core contracts, HTTP gateway, provider adapter, browser UI, memory, or RAG. A full app can still be installed in one command when the goal is <stackline-ai-studio> connected to Ollama.
| Feature | Supported |
|---|---|
| Provider-neutral core contracts | ✅ |
| Fetch-compatible backend HTTP handler | ✅ |
| Ollama provider adapter | ✅ |
Framework-neutral <stackline-ai-studio> web component |
✅ |
| Model listing and model picker | ✅ |
| SQLite conversation memory for local/private apps | ✅ |
| PostgreSQL read-only RAG retriever | ✅ |
| Safe Markdown and limited safe HTML rendering in UI | ✅ |
| LocalStorage history with quota protection | ✅ |
| English, Portuguese, French, and Spanish UI labels | ✅ |
| Backend-first security boundary | ✅ |
| Scenario-based install documentation | ✅ |
- Read This First
- Packages
- Install By Scenario
- End-To-End Minimal App
- Verify Before Opening The UI
- Public Local Demo
- Full Tutorial
- Development
- Examples
- Security
- Community
- License
<stackline-ai-studio></stackline-ai-studio> is the browser UI only. It does
not talk to Ollama directly, it does not keep provider keys, and it does not
open databases.
A working app needs this path:
Browser
-> @stackline/ai-ui
-> GET /api/ai/models
-> POST /api/ai/chat
-> @stackline/ai-server
-> @stackline/ai
-> @stackline/ai-ollama
-> Ollama
Memory and RAG are backend-only additions:
@stackline/ai
-> @stackline/ai-memory-sqlite
-> @stackline/ai-rag-postgres
Provider keys, database URLs, SQL, RAG filters, and memory paths stay on the backend.
| Package | Responsibility | Runtime |
|---|---|---|
@stackline/ai |
Core contracts, model listing, chat orchestration, RAG, memory capture | backend/shared |
@stackline/ai-server |
Fetch-compatible HTTP handler for /health, /manifest, /models, /chat |
backend |
@stackline/ai-ollama |
Ollama provider adapter | backend |
@stackline/ai-memory-sqlite |
SQLite/sql.js conversation memory | backend |
@stackline/ai-rag-postgres |
Read-only PostgreSQL RAG retriever | backend |
@stackline/ai-ui |
Framework-neutral Studio web component | browser |
Do not install only the UI package unless you already have a compatible backend. Choose the command that matches what you are building.
Custom provider or contract tests, no HTTP and no UI:
npm init -y
npm pkg set type=module
npm install @stackline/aiBackend code that calls Ollama directly, no HTTP and no UI:
npm init -y
npm pkg set type=module
npm install @stackline/ai @stackline/ai-ollamaCreates /api/ai/models and /api/ai/chat:
npm init -y
npm pkg set type=module
npm install @stackline/ai @stackline/ai-server @stackline/ai-ollamaThis is the normal install when you want
<stackline-ai-studio></stackline-ai-studio> to actually work:
npm init -y
npm pkg set type=module
npm install @stackline/ai @stackline/ai-server @stackline/ai-ollama @stackline/ai-ui
npm install -D vitenpm install @stackline/ai @stackline/ai-server @stackline/ai-ollama @stackline/ai-ui @stackline/ai-memory-sqlite
npm install -D vite
mkdir -p datanpm install @stackline/ai @stackline/ai-server @stackline/ai-ollama @stackline/ai-ui @stackline/ai-rag-postgres
npm install -D viteUI, backend, Ollama, SQLite memory, and PostgreSQL RAG:
npm install @stackline/ai @stackline/ai-server @stackline/ai-ollama @stackline/ai-ui @stackline/ai-memory-sqlite @stackline/ai-rag-postgres
npm install -D vite
mkdir -p data sql srcDetailed installation guide:
docs/getting-started/install-by-scenario.md
Create a folder:
mkdir stackline-ai-starter
cd stackline-ai-starter
npm init -y
npm pkg set type=module
npm install @stackline/ai @stackline/ai-server @stackline/ai-ollama @stackline/ai-ui
npm install -D viteCheck Ollama and choose a real model name:
ollama list
ollama pull llama3.1
curl http://127.0.0.1:11434/api/tagsIf your installed model is not llama3.1, use the exact NAME from
ollama list.
Create .env:
PORT=8787
WEB_ORIGIN=http://localhost:4623
OLLAMA_TARGET=http://127.0.0.1:11434
OLLAMA_MODEL=llama3.1Create index.js:
import { createServer } from "node:http";
import { existsSync, readFileSync } from "node:fs";
import { createStacklineAIServer } from "@stackline/ai/server";
import { createStacklineAIHttpHandler } from "@stackline/ai-server";
import { ollamaProvider } from "@stackline/ai-ollama";
function loadEnv(path = new URL(".env", import.meta.url)) {
if (!existsSync(path)) return;
for (const line of readFileSync(path, "utf8").split(/\r?\n/)) {
const match = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/);
if (!match || process.env[match[1]]) continue;
process.env[match[1]] = match[2].replace(/^['"]|['"]$/g, "");
}
}
async function requestFromNode(req) {
const chunks = [];
for await (const chunk of req) chunks.push(chunk);
return new Request(`http://${req.headers.host || "localhost"}${req.url}`, {
method: req.method,
headers: req.headers,
body: chunks.length ? Buffer.concat(chunks) : undefined,
});
}
async function writeNodeResponse(res, response) {
res.statusCode = response.status;
response.headers.forEach((value, key) => res.setHeader(key, value));
res.end(Buffer.from(await response.arrayBuffer()));
}
loadEnv();
const model = process.env.OLLAMA_MODEL || "auto";
if (!model.trim()) throw new Error("OLLAMA_MODEL is empty.");
const ai = createStacklineAIServer({
provider: ollamaProvider({
target: process.env.OLLAMA_TARGET || "http://127.0.0.1:11434",
model,
}),
rag: false,
memory: false,
});
const handleAI = createStacklineAIHttpHandler({
server: ai,
basePath: "/api/ai",
cors: { origins: [process.env.WEB_ORIGIN || "http://localhost:4623"] },
});
const server = createServer(async (req, res) => {
try {
await writeNodeResponse(res, await handleAI(await requestFromNode(req)));
} catch (cause) {
const message = cause instanceof Error ? cause.message : "Unexpected server error.";
res.writeHead(500, { "content-type": "application/json; charset=utf-8" });
res.end(JSON.stringify({ error: { message, status: 500 } }));
}
});
server.listen(Number(process.env.PORT || 8787), () => {
console.log("Stackline AI API: http://127.0.0.1:8787/api/ai");
});Create index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Stackline AI Starter</title>
</head>
<body>
<stackline-ai-studio
endpoint="/api/ai/chat"
models-endpoint="/api/ai/models"
model="llama3.1"
theme="material"
language="en"
storage-key="stackline-ai-starter"
></stackline-ai-studio>
<script type="module" src="/src/index.js"></script>
</body>
</html>Create src/index.js:
import "@stackline/ai-ui";Create vite.config.js:
import { defineConfig } from "vite";
export default defineConfig({
server: {
host: "0.0.0.0",
port: 4623,
proxy: {
"/api/ai": "http://127.0.0.1:8787",
},
},
});Run the backend and frontend in two terminals:
node index.jsnpx vite --host 0.0.0.0 --port 4623Open:
http://localhost:4623/
curl http://127.0.0.1:8787/api/ai/health
curl http://127.0.0.1:8787/api/ai/models
curl http://127.0.0.1:8787/api/ai/chat \
-H 'content-type: application/json' \
-d '{"model":"llama3.1","messages":[{"role":"user","content":"Reply with one short sentence."}]}'If the chat request returns:
Ollama chat requires a model. Use a model name or model: "auto".
then the model is empty or auto could not resolve an installed model. Run
ollama list, copy the exact NAME, set OLLAMA_MODEL, and set the UI
model attribute to the same value.
pnpm install
pnpm --filter stackline-ai-local-demo startOpen:
http://localhost:4622/
The local demo uses a fake provider and in-memory RAG documents. It does not use Ollama keys, PostgreSQL, SQLite memory, or private databases.
docs/getting-started/full-stack-tutorial.mddocs/concepts/architecture.mddocs/reference/http-api.mddocs/guides/production.mddocs/getting-started/troubleshooting.md
Repository tooling requires Node >=22.13.0 because this workspace uses
pnpm@11.22.0.
corepack enable
pnpm install
pnpm run checkpnpm run check runs lint, typecheck, tests, build, example smoke tests, and
package dry-run checks.
examples/local-demoexamples/ollama-minimalexamples/full-stack-viteexamples/express-adapterexamples/sqlite-memoryexamples/postgres-ragexamples/complete-stack
Never expose provider API keys, Ollama Cloud keys, database credentials, SQL, or memory paths in browser code. Add authentication, authorization, restrictive CORS, rate limits, body limits, model allow-lists, tenant filters, and logging policy in production.
https://www.reddit.com/r/Stackline/
MIT