Quickstart

Cut your agent's token bill by 97% in under 5 minutes.
Start with natural language — no schemas, no structured queries required.

What is Nocturnus.AI? A context optimization engine that cuts your agent's token costs by 97%. Feed it plain English, it stores structured facts. Ask questions, get verified answers. Your agents connect via MCP, Python SDK, TypeScript SDK, or HTTP — and the Context Management Engine ensures they only pay for relevant tokens.
Prerequisites
  • Docker Desktop 24+ with Compose V2 (docker compose, not docker-compose)
  • For Steps 2–3 (natural language): set one of ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY
  • Steps 4–5 (direct API and MCP) work without any LLM key
Install with AI

Copy a prompt into your AI coding assistant and it will install NocturnusAI for you.

Claude Code
Install NocturnusAI on my machine. Run: curl -fsSL https://raw.githubusercontent.com/Auctalis/nocturnusai/main/install.sh | bash — then verify with: curl http://localhost:9300/health
GitHub Copilot
@terminal Install NocturnusAI: curl -fsSL https://raw.githubusercontent.com/Auctalis/nocturnusai/main/install.sh | bash
Cursor
Run this in my terminal to install NocturnusAI: curl -fsSL https://raw.githubusercontent.com/Auctalis/nocturnusai/main/install.sh | bash
STEP 1 · INSTALL

Start the Server

One command. Installs Docker Compose stack, waits for healthy, and installs the native CLI binary:

$ curl -fsSL https://raw.githubusercontent.com/Auctalis/nocturnusai/main/install.sh | bash

# With an API key for LLM features (enables /extract and /synthesize in Steps 2–3):
$ curl -fsSL https://raw.githubusercontent.com/Auctalis/nocturnusai/main/install.sh | bash -s -- --key sk-ant-...

# With local Ollama (free, no API key needed — install Ollama first):
$ curl -fsSL https://raw.githubusercontent.com/Auctalis/nocturnusai/main/install.sh | bash -s -- --host-ollama

Verify it's running:

$ curl http://localhost:9300/health

{ "status": "healthy" }
Data persistence — Facts survive container restarts. Docker Compose mounts a ./data directory for WAL logs and snapshots. Delete that folder to wipe the knowledge base and start fresh.
CLI installed. The installer places the nocturnusai native binary on your PATH. Run nocturnusai for an interactive REPL, or use nocturnusai -e "tell ..." in scripts.
STEP 2 · NATURAL LANGUAGE

Feed It Text, Ask It Questions

The fastest way to get started. Set an LLM API key — ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY — and NocturnusAI handles fact extraction and Q&A automatically.

Extract facts from plain text:

$ curl -X POST http://localhost:9300/extract \
    -H "Content-Type: application/json" \
    -d '{
    "text": "Acme Corp is on the enterprise plan and is based in Austin. They get 24/7 SLA support.",
    "assert": true
  }'
{
  "facts": [
    { "predicate": "customer_tier", "args": ["acme_corp", "enterprise"] },
    { "predicate": "location", "args": ["acme_corp", "austin"] },
    { "predicate": "sla_tier", "args": ["acme_corp", "24_7"] }
  ],
  "asserted": true
}

Ask a natural language question — get a sourced answer:

$ curl -X POST http://localhost:9300/synthesize \
    -H "Content-Type: application/json" \
    -d '{"question": "What support level does Acme Corp get?"}'
{
  "answer": "Acme Corp gets 24/7 SLA support on their enterprise plan.",
  "derivation": [
    { "fact": "sla_tier(acme_corp, 24_7)" },
    { "fact": "customer_tier(acme_corp, enterprise)" }
  ],
  "confidence": 0.97
}
Not a guess. The derivation field shows the exact facts that produced this answer. This is verification — if the fact isn't in the KB, the answer says so rather than making something up.
Even simpler: POST /context

Skip extraction and synthesis — just send your conversation turns and get ranked facts back:

POST /context
{ "turns": ["Acme is on enterprise plan", "They have 24/7 SLA"] }

→ { "facts": [
    {"predicate":"customer_tier", "args":["acme","enterprise"], "salience":0.95},
    {"predicate":"sla_tier", "args":["acme","24_7"], "salience":0.90}
  ],
  "factsReturned": 2, "contradictions": 0
}

Feed these facts to GPT-4o or Claude — 200 tokens instead of 150K. Full guide →

STEP 3 · MCP CONNECT

Connect Any Agent in 30 Seconds

NocturnusAI is an MCP server. Any MCP-compatible agent, IDE, or framework connects with a two-line config — no SDK, no API wrapper, no code changes required.

Cursor / Windsurf (.cursor/mcp.json):

{
  "mcpServers": {
    "nocturnus": {
      "url": "http://localhost:9300/mcp/sse"
    }
  }
}

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "nocturnus": {
      "url": "http://localhost:9300/mcp/sse",
      "transport": "sse"
    }
  }
}

Your agent immediately gets 9 tools: tell, ask, teach, forget, recall, context, compress, cleanup, predicates.

That's it. No API wrappers, no schemas to define, no integration code. The MCP tools are backed by the full reasoning engine — your agent can ask questions in natural language and get verified answers.
Context optimization built in. Once connected, use POST /context/optimize with goals to get only the facts your agent needs — 97% fewer tokens billed per request. Learn about context optimization →
STEP 4 · DIRECT API

Structured Facts & Queries

Use the structured API directly — no LLM key required. Facts are stored as typed predicates, giving you deterministic pipelines without any LLM in the extraction path. These are the same endpoints the MCP tools call internally.

Store a structured fact:

$ curl -X POST http://localhost:9300/tell \
    -H "Content-Type: application/json" \
    -d '{"predicate": "customer_tier", "args": ["acme_corp", "enterprise"]}'

{ "status": "ok", "atom": "customer_tier(acme_corp, enterprise)" }

Query with a variable (the ? prefix marks unknowns):

$ curl -X POST http://localhost:9300/ask \
    -H "Content-Type: application/json" \
    -d '{"predicate": "customer_tier", "args": ["acme_corp", "?tier"]}'

{ "results": ["customer_tier(acme_corp, enterprise)"] }
Going deeper? Teach rules and watch the inference engine derive new facts automatically. See Core Concepts → for the full picture on reasoning, scopes, and truth maintenance.
STEP 5 · BUILD AN AGENT

LangChain Agent with Verified Knowledge

Install the Python SDK with LangChain integration:

$ pip install nocturnusai[langchain] langchain-anthropic

A complete working agent in 20 lines:

from nocturnusai import SyncNocturnusAIClient
from nocturnusai.langchain import get_nocturnusai_tools
from langchain_anthropic import ChatAnthropic
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate

# Connect to Nocturnus — get 4 LangChain tools backed by the reasoning engine
client = SyncNocturnusAIClient("http://localhost:9300")
tools = get_nocturnusai_tools(client)
# → assert, query, infer, context

llm = ChatAnthropic(model="claude-sonnet-4-6")
prompt = ChatPromptTemplate.from_messages([
    ("system", "Use your tools to store and retrieve verified facts. Never guess."),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools)

result = executor.invoke({
    "input": "Remember: Acme Corp is on the enterprise plan. Now — what plan are they on?"
})
print(result["output"])
# Agent gets optimized facts from /context — 200 tokens, not 150K.
# Correct. Sourced. 750x cheaper than context stuffing.
Acme Corp is on the enterprise plan. (verified from knowledge base)
Your agent now reasons over facts, not token weights. The knowledge persists across sessions and is immediately shared with any other agent on the same server.

Running From Source

Skip Docker if you're contributing to the codebase or prefer to run the JVM directly. Requires JDK 17+.

$ git clone https://github.com/Auctalis/nocturnusai.git
$ cd nocturnusai

# Run the HTTP API server on :9300
$ ./gradlew :nocturnusai-server:run

# Run the interactive REPL (connects to a running server)
$ ./gradlew :nocturnusai-cli:run

# Run all tests
$ ./gradlew test

LLM keys work the same way — set them as environment variables before running Gradle, or add them to a .env file loaded by your shell.


Environment Variables

Quick reference for all configuration variables. Copy into a .env file or pass directly to Docker Compose / Gradle.

Variable Default Purpose
PORT 9300 Server port
HOST 0.0.0.0 Bind address
API_KEY none Legacy single-key auth. Set this or use AUTH_ENABLED=true for full RBAC.
CORS_ALLOWED_ORIGINS localhost:3000, 5173, 8080 Comma-separated allowed origins. Set to * only for fully public read-only APIs.
MAX_REQUEST_BODY_BYTES 10485760 (10 MB) Maximum allowed request body size. Requests exceeding this return 413.
STORAGE_DIR ./data WAL and snapshot directory
ANTHROPIC_API_KEY none Enables /extract and /synthesize using Claude
OPENAI_API_KEY none Enables LLM features using GPT-4o
GOOGLE_API_KEY none Enables LLM features using Gemini
OLLAMA_BASE_URL none Enables LLM features using a local Ollama instance
EXTRACTION_ENABLED false (true in Docker) Toggle /extract and /synthesize endpoints. The official Docker image sets this to true automatically.
LLM_MODEL provider default Override the LLM model (e.g. claude-sonnet-4-6)
LLM_TEMPERATURE 0.1 Lower = more deterministic fact extraction
AUTH_ENABLED false Enable role-based auth. When true, requires admin bootstrap on first run.
NOCTURNUSAI_ADMIN_USER admin Bootstrap admin username — change before exposing to any network
NOCTURNUSAI_ADMIN_PASS nocturnusai Bootstrap admin password — change before exposing to any network
API_KEY_DEFAULT_EXPIRY_DAYS none (no expiry) Default expiry for new API keys in days. Recommended: 365 for production.
ENCRYPTION_KEY none 64 hex-char AES-256 key for at-rest encryption. Generate with openssl rand -hex 32
TLS_ENABLED false Enable HTTPS on TLS_PORT
TLS_PORT 9443 HTTPS port when TLS is enabled
TLS_KEYSTORE_PATH none Path to JKS or PKCS12 keystore file
TLS_KEYSTORE_PASSWORD none Keystore password
REPLICATION_MODE LEADER LEADER or FOLLOWER
LEADER_URL none Leader URL when running as a follower

Troubleshooting

Port 9300 is already in use

Another process is bound to that port. Either stop it, or start Nocturnus on a different port:

$ PORT=9301 docker compose up -d
$ curl http://localhost:9301/health

docker-compose command not found

You're running Compose V1. The docs use Compose V2 syntax (docker compose with a space). Update Docker Desktop to 24+ or install the Compose plugin.

/extract returns "LLM provider not configured"

The server started without an LLM API key. Stop the container, then restart with the key:

$ docker compose down
$ ANTHROPIC_API_KEY=sk-ant-... docker compose up -d

/ask returns empty results

Two common causes:

Check what's actually stored:

$ curl http://localhost:9300/predicates

Facts are gone after restart

The ./data directory holds all WAL logs and snapshots. If it was deleted, facts won't survive a restart. Make sure Docker Compose mounts it as a volume — the default docker-compose.yml already does this. If you're running from source, ensure STORAGE_DIR points to a persistent path.



What's Next?

Integrations →

Connect to LangChain, CrewAI, AutoGen, and more

Core Concepts →

Facts, rules, inference, scopes, and salience scoring

API Reference →

Every endpoint with full request/response shapes

FAQ →

Common questions about NocturnusAI