TWO-HALVES platform overview
☤ built on a forked Hermes Agent core

One graph engine.
Knowledge on one side, app-building on the other.

Two-Halves is a platform for retrieval-grounded knowledge work and visual enterprise app-building, sharing one harness / loop / graph foundation underneath. It started as a fork of Hermes Agent's real agent core — memory, tool execution, the agent loop — evolved into its own product rather than kept as an external dependency.

Retrieval: keyword · vector · hybrid · graph Graph engine: custom, checkpointed, CEL-gated Frontend: SvelteKit, terminal-styled Backend: FastAPI + SQLite
One brain, two halves — knowledge on the left, app-building on the right.
01

The two halves

Knowledge

Retrieval-grounded chat & wiki

Chat, wiki synthesis, and retrieval all run through the same graph engine — retrieval strategy is a node config, not a separate subsystem.

  • Four retrieval strategies: keyword (FTS5), vector, hybrid, and graph (entity search → relation expansion → chunk resolve)
  • Agentic RAG as a composed loop-back pattern, not a bespoke engine
  • LLM-extracted knowledge graph and section-locked wiki synthesis
  • Real, persistent multi-turn sessions with a live history sidebar
  • An expandable trace panel — see exactly which chunks and nodes fed each answer
App-Builder

Visual composer for enterprise apps

Drag nodes, wire edges, configure per-node-type forms — an app built here runs on the exact same execution path as chat.

  • Node/edge canvas over the same graph primitives chat uses
  • Apps can reference other apps as subgraph nodes
  • Org/SSO via OIDC, role-based admin, and a real audit log
  • API keys, free-tier quota enforcement, GST invoicing scaffolding
  • Google Workspace / Slack / Notion / generic REST-GraphQL / Postgres-MySQL connectors
02

What's actually built

Graph RAG

A real graph retrieval strategy — FTS5 entity-name search, one-hop relation expansion, resolved back to real chunk text. Configurable expansion depth.

Agentic RAG

A retriever + evaluator loop, gated by a CEL condition on a loop-back edge, with an explicit round cap — composed from existing primitives, not a new engine.

Session persistence

Real multi-turn continuity backed by the same session store Hermes's own CLI uses, scoped per account so nothing crosses between callers.

Custom graph engine

Checkpoint-to-disk after every node, pause/resume, human-approval gates, parallel fan-out/fan-in with deterministic declaration-order merging.

Sandboxed harness

Seven execution backends behind one interface, with approval-gated dangerous commands and per-node-type metering wired in from day one.

Enterprise layer

Real OIDC SSO verified against a disposable identity provider, seat limits, role-based access, and an audit log that also records rejected access attempts.

Managed hosting

Per-tenant isolated SQLite, verified with real, structurally-separated Docker containers — not a shared-database rewrite.

India-first billing

Razorpay integration, GST-compliant invoice numbering (financial-year-scoped), and DPDP-oriented consent and deletion flows.

03

Status, honestly

Phases 0–12foundation through the enterprise layer, all verified live against real runs, not just written down.
Hardening passreal flagged gaps closed after Phase 12, including a live-verified graph-orchestrated database write and a real FTS5 parser bug fixed the same day it was found.
Managed hostingarchitecture chosen and verified locally with real Docker containers; no paid cloud deployment yet.
Payments & native connectorsbuilt against real APIs, unverified live — no sandbox credentials exist yet for Razorpay, Google Workspace, Slack, or Notion.
New connectors & embedding researchdeliberately deferred, gated on real demand that doesn't exist yet.
04

How it's built

Engine core
Forked from Hermes Agent via git subtree — full upstream history preserved and walkable, not squashed. The fork is evolved directly, not consumed over HTTP.
Graph engine
Custom-built, using LangGraph only as a design reference. Loop-back edges are just backwards edges gated by a CEL condition — never sandboxed JS eval.
Retrieval
Not a separate RAG subsystem — every strategy (keyword, vector, hybrid, graph) is a config value on a retriever node type.
Storage
One SQLite file per concern (knowledge, wiki, apps, billing, enterprise), every record stamped with a shared account id so billing never needs a cross-store join.
Frontend
A fresh SvelteKit build, deliberately not a fork of Open WebUI — its branding-protection license terms made that the wrong foundation.
Embeddings
One connector active at a time; every vector record carries the connector's id, so swapping models is an explicit re-embed migration, never a silent mix of incompatible spaces.