Go SDK and reference stack for a self-hosted second brain: Markdown knowledge base → Neo4j graph + Qdrant vectors → Matrix RAG bot, with an optional low-latency voice assistant (STT/TTS).
Built on go-matrix-bot for Matrix E2E bots and go-config for YAML + env configuration.
A minimal synthetic fixture lives in examples/corpus/ for ingest and RAG smoke tests — replace it with your own Markdown tree locally.
graph TB
subgraph "Knowledge Base"
MD["examples/corpus/*.md"]
DS["docsparse<br/>SUBJ / UC / PAIN IDs"]
end
subgraph "go-second-brain"
ING["cmd/ingestor"]
RAG["internal/rag"]
BOT["cmd/bot"]
VA["cmd/assistant"]
PKG["pkg/* SDK"]
end
subgraph "Storage"
N4J["Neo4j graph"]
QD["Qdrant vectors"]
end
subgraph "AI"
OL["Ollama<br/>embed + generate"]
end
subgraph "Matrix"
MX["Synapse / homeserver"]
RM["💬 Room"]
end
subgraph "Voice (optional)"
IW["Inworld STT"]
CT["Cartesia TTS"]
end
MD --> DS --> ING
ING --> N4J
ING --> QD
ING --> OL
RM --> MX --> BOT
BOT --> RAG
RAG --> QD
RAG --> OL
BOT --> PKG
VA --> IW
VA --> CT
BOT -.->|"E2E via"| MBot["go-matrix-bot"]
One-shot or scheduled indexing of a documentation tree.
sequenceDiagram
participant Docs as examples/corpus
participant Ingestor as cmd/ingestor
participant Neo4j
participant Qdrant
participant Ollama
Ingestor->>Docs: walk + chunk (docsparse)
Ingestor->>Neo4j: write nodes/edges
loop each chunk
Ingestor->>Ollama: POST /api/embeddings
Ollama-->>Ingestor: vector
Ingestor->>Qdrant: upsert point
end
Users ask in a Matrix room; the bot retrieves chunks and generates an answer.
sequenceDiagram
participant User
participant Matrix
participant Bot as cmd/bot
participant Qdrant
participant Ollama
User->>Matrix: !brain What does UC-01 describe?
Matrix->>Bot: event
Bot->>Ollama: embed query
Bot->>Qdrant: vector search (top-k)
Qdrant-->>Bot: chunks
Bot->>Ollama: generate with system prompt
Ollama-->>Bot: answer
Bot->>Matrix: markdown reply @User
Matrix->>User: grounded answer
Low-latency STT → TTS loop for hands-free use (no RAG in MVP path).
sequenceDiagram
participant Mic
participant Assistant as cmd/assistant
participant Inworld
participant Cartesia
participant Speaker
Mic->>Assistant: PCM stream
Assistant->>Inworld: streaming STT
Inworld-->>Assistant: transcript
Assistant->>Cartesia: streaming TTS
Cartesia-->>Assistant: audio
Assistant->>Speaker: playback
graph LR
subgraph "Host"
OL2["Ollama :11434"]
end
subgraph "Docker compose"
N["Neo4j"]
Q["Qdrant"]
I["kg-ingestor"]
B["matrix-bot"]
end
MD2["examples/corpus"] --> I
I --> N
I --> Q
I --> OL2
B --> N
B --> Q
B --> OL2
go get github.com/eSlider/go-second-brain/servicesOptional sibling libraries (used by this repo or common in the same stack):
go get github.com/eslider/go-matrix-bot # Matrix E2E bot engine
go get github.com/eslider/go-config # YAML + env config merge
go get github.com/eslider/go-ollama # standalone Ollama client (alternative)System dependency (required for cmd/bot / Matrix E2E):
# Debian/Ubuntu
sudo apt-get install libolm-dev gccgit clone https://github.com/eSlider/go-second-brain.git
cd go-second-brain
cp config.yaml.example config.yaml # optional overrides
cp .env.example .env # secrets: NEO4J_PASSWORD, MATRIX_PASSWORD, …docker run -d -p 11434:11434 -v ollama-data:/root/.ollama ollama/ollama
ollama pull embeddinggemma
ollama pull cajina/gemma4_e2b-q4_k_s:v01Intel GPU acceleration: ollama-intel-gpu — same OLLAMA_URL, no code changes.
make kg-up
make ingest
make bot- Neo4j Browser: http://localhost:7474
- Bot command prefix:
!brain(BOT_COMMAND_PREFIX) - Agent / SDK docs: docs/system/README.md
import (
"context"
"time"
"github.com/eSlider/go-second-brain/services/pkg/ollama"
"github.com/eSlider/go-second-brain/services/pkg/qdrant"
)
ctx := context.Background()
llm, err := ollama.New(ctx, &ollama.Config{URL: "http://127.0.0.1:11434", Timeout: 120 * time.Second})
if err != nil {
panic(err)
}
defer llm.Close()
vec, err := llm.Embed(ctx, "embeddinggemma", "sample workflow knowledge node")
if err != nil {
panic(err)
}
q, err := qdrant.New(ctx, &qdrant.Config{URL: "http://127.0.0.1:6333", Collection: "knowledge"}, 30*time.Second)
if err != nil {
panic(err)
}
defer q.Close()
hits, err := q.Search(ctx, "knowledge", vec, 8)
_ = hitscd services
# INWORLD_API_KEY, CARTESIA_API_KEY, CARTESIA_VOICE_ID in .env
go run ./cmd/assistant| Package | pkg.go.dev | Role |
|---|---|---|
pkg/ollama |
embeddings + generate | Ollama HTTP client |
pkg/qdrant |
vector CRUD + search | Qdrant REST client |
pkg/neo4j |
driver wrapper | Neo4j connectivity |
pkg/matrix |
Matrix config | Homeserver / bot DB settings |
pkg/documents |
docs root path | Ingestion corpus root |
pkg/inworld |
streaming STT | Inworld WebSocket client |
pkg/cartesia |
streaming TTS | Cartesia WebSocket client |
pkg/httpjson |
JSON HTTP helper | Shared HTTP JSON transport |
pkg/botcmd |
command prefix | Bot command settings |
internal/* is app wiring (RAG, docsparse, config loader) — not a stability promise for external importers. See ADR-0003.
| Binary | Profile | Description |
|---|---|---|
cmd/ingestor |
kg |
Walk examples/corpus (or DOCS_ROOT), write Neo4j + Qdrant |
cmd/bot |
bot |
Matrix RAG bot via go-matrix-bot |
cmd/assistant |
— | Low-latency STT/TTS CLI |
Defaults in config.yaml.example, secrets in .env.example. Loaded via go-config: YAML → .env → process env.
| Variable | Required | Component | Description |
|---|---|---|---|
NEO4J_URI |
ingest/bot | Neo4j | Bolt URI |
NEO4J_USER |
ingest/bot | Neo4j | Username |
NEO4J_PASSWORD |
ingest/bot | Neo4j | Password |
QDRANT_URL |
ingest/bot | Qdrant | REST base URL |
QDRANT_COLLECTION |
ingest/bot | Qdrant | Collection name (default knowledge) |
OLLAMA_URL |
ingest/bot | Ollama | API base URL |
EMBED_MODEL |
ingest/bot | Ollama | Embedding model |
GEN_MODEL |
bot | Ollama | Generation model |
MATRIX_API_URL |
bot | Matrix | Homeserver URL |
MATRIX_USER |
bot | Matrix | Bot localpart |
MATRIX_PASSWORD |
bot | Matrix | Bot password |
BOT_COMMAND_PREFIX |
bot | Bot | Default !brain |
INWORLD_API_KEY |
assistant | Inworld | STT API key |
CARTESIA_API_KEY |
assistant | Cartesia | TTS API key |
CARTESIA_VOICE_ID |
assistant | Cartesia | Voice ID |
CONFIG_PATH |
all | Config | Optional path to repo / config file |
Details: docs/system/configuration.md
| Library | Description | Install |
|---|---|---|
| go-matrix-bot | Matrix bots with E2E encryption | go get github.com/eslider/go-matrix-bot |
| go-config | YAML / env / JSON config merge | go get github.com/eslider/go-config |
| go-ollama | Ollama + Open WebUI streaming client | go get github.com/eslider/go-ollama |
| ollama-intel-gpu | SYCL-accelerated Ollama on Intel GPU | Docker compose stack |
cd services && go test ./...
make test-integration # testcontainers (Neo4j, Qdrant)
make lintSee CONTRIBUTING.md.