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–12 — foundation through the enterprise layer, all verified live against real runs, not just written down.
Hardening pass — real 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 hosting — architecture chosen and verified locally with real Docker containers; no paid cloud deployment yet.
Payments & native connectors — built against real APIs, unverified live — no sandbox credentials exist yet for Razorpay, Google Workspace, Slack, or Notion.
New connectors & embedding research — deliberately 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.