The Problem
Self‑hosted AI assistants often rely on ad‑hoc file storage and a single‑user scheduler, which makes concurrent use brittle and creates a large attack surface when secrets are checked into the repo. OpenClaw’s memory lives in a flat MEMORY.md, its scheduler is a hard‑coded heartbeat loop, and credentials are scattered in plaintext files.
What This Does
OpenLobster replaces the markdown memory with a proper graph store (Neo4j) and a lightweight file backend (apps/backend/internal/application/graphql/dto/adapters.go). User sessions, channel histories and tool permissions are first‑class entities stored in the database (apps/backend/internal/infrastructure/persistence/database.go). The original heartbeat daemon is swapped for a configurable cron‑style scheduler (apps/backend/internal/domain/services/scheduler/scheduler_service.go). The frontend (apps/frontend/src/App.tsx) talks to the GraphQL API via the client in apps/frontend/src/graphql/client.ts.
How It Is Wired
Execution begins at apps/backend/cmd/openlobster/main.go → main (line 39) which invokes the Execute function (called from 90 places). Execute reaches out over the network via t.Tools.Browser.Fetch (a browser tool wrapper) and eventually starts the HTTP server defined in apps/backend/cmd/openlobster/serve/app.go → Run. Run builds the GraphQL server (NewGraphQLServer – 76 callers) and the database connection (GormDB – 111 callers).
From the server, request handling flows through the health endpoint (ServeHTTP in apps/backend/internal/application/health/handler.go) and webhook handlers (serveTwilio, serveWhatsApp). The most widely used internal symbols are Close (135 callers) and New (109 callers), giving them the highest blast radius.
The frontend entry apps/frontend/src/App.tsx imports 23 other modules (hub) and participates in a circular import cycle with Modal and AccessTokenModal. The GraphQL client (apps/frontend/src/graphql/client.ts) contains 14 branch points in 44 lines, contributing to cognitive load.
Database writes are performed in resolver tests such as apps/backend/internal/application/graphql/resolvers/resolver_test.go, which also triggers cryptographic helpers and file I/O, making that test file a hot spot (162 functions, 62 callers).
How To Use It
# Clone the repo
git clone https://github.com/moses-y/OpenLobster
cd OpenLobster
# Install pnpm (if not present) and install JS/TS deps
pnpm install # reads apps/frontend/package.json and apps/backend/package.json
# Build the backend container (base image pinned by digest is recommended)
docker build -f .docker/Dockerfile.basic -t openlobster:latest .
# Run Neo4j (or use the file backend) – see docs/architecture for connection details
docker run -d --name neo4j -p 7474:7474 neo4j:5
# Start the backend (binary produced by the Go build)
go build -o bin/openlobster ./apps/backend/cmd/openlobster
./bin/openlobster serve # entry point main → Execute → Run → HTTP server
# In another terminal, start the UI
pnpm --filter frontend dev # runs Vite per vite.config.ts
Configuration lives in apps/backend/cmd/openlobster/config/config.go and is overridden by environment variables. The repository currently commits a development .env file (apps/frontend/.env.development) that must be removed and replaced with a .env.example before production use.
Real‑World Use
A company can deploy the Docker image behind its internal network, point the UI at http://localhost:3000, and let each employee interact with the same agent via Slack, Discord or Twilio. The agent stores per‑user conversation graphs in Neo4j, enabling personalized context without file‑based clashes. Scheduler jobs (e.g., nightly data cleanup) are defined in the database and executed by scheduler_service.go.
Code Health & Issues
Static analysis findings (68 total):
- High – Import cycles (14 files, e.g.,
App.tsx,Modal/index.ts) – break cycles by extracting shared types. - Medium – High branching density in
apps/frontend/src/graphql/client.ts– refactor to strategy tables. - High – Deep nesting (max depth 8) in several UI components – flatten with early returns.
- Medium – Hub modules (
App.tsx,graphql/client.ts) – keep these stable, move volatile logic out. - High – Duplicated code blocks across daemon and migration files – extract common helpers.
- High – Oversized files (e.g.,
schemas/config.schema.ts> 600 lines) – split by responsibility.
Code‑health audit (8 findings):
- HIGH Pin GitHub Actions to commit SHAs (
.github/workflows/*). - HIGH Remove committed
.env.developmentand rotate its secrets. - MEDIUM Declare least‑privilege
GITHUB_TOKENpermissions (tests.backend-ci.yaml). - MEDIUM Pin Docker base images by digest (
.docker/Dockerfile.basic). - MEDIUM Add a dependency‑vulnerability scan to CI.
- MEDIUM Install a pre‑commit secret‑scan hook.
- MEDIUM Set
persist-credentials: falseon checkout inrelease.upload-binaries.yml. - LOW Define
timeout-minuteson workflow jobs (release.docker-images.yaml).
The Bottom Line
OpenLobster delivers a functional, multi‑user AI assistant with a proper graph backend and a configurable scheduler, but the codebase suffers from import cycles, deep nesting and duplicated platform‑specific logic. It is suitable for teams comfortable fixing architectural debt and enforcing stricter CI/CD hygiene before production deployment.