Switch memory provider to hindsight
Check Flake / check-flake (push) Successful in 21m43s

This commit is contained in:
2026-06-04 10:32:17 -07:00
parent 1551e5b02b
commit 2e1146ea68
6 changed files with 218 additions and 8 deletions
+1
View File
@@ -31,6 +31,7 @@ in
];
nixpkgs.overlays = [
hostConfig.inputs.self.overlays.default
hostConfig.inputs.claude-code-nix.overlays.default
];
Generated
+17
View File
@@ -267,6 +267,22 @@
"type": "github"
}
},
"hindsight-src": {
"flake": false,
"locked": {
"lastModified": 1780589667,
"narHash": "sha256-Zb8zIdlnm9spUiVbGdByGKE/V/5q+RKjbuSbayNIDxY=",
"owner": "vectorize-io",
"repo": "hindsight",
"rev": "7683f29004ab9d88e0ef3f0f18b8ffe6fc741905",
"type": "github"
},
"original": {
"owner": "vectorize-io",
"repo": "hindsight",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
@@ -441,6 +457,7 @@
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"hermes-agent": "hermes-agent",
"hindsight-src": "hindsight-src",
"home-manager": "home-manager",
"microvm": "microvm",
"nix-index-database": "nix-index-database",
+7
View File
@@ -94,6 +94,13 @@
uv2nix.inputs.pyproject-nix.follows = "hermes-agent/pyproject-nix";
};
};
# Hindsight memory server (vectorize-io). No upstream flake; consumed as a
# bare source tree and packaged via the uv2nix toolchain from hermes-agent.
hindsight-src = {
url = "github:vectorize-io/hindsight";
flake = false;
};
};
outputs = { self, nixpkgs, ... }@inputs:
+112 -8
View File
@@ -21,6 +21,9 @@
extraPackages = with pkgs; [ nix git ripgrep fd jq codex ];
# Pulls in hindsight-client (the HTTP client lib the memory plugin uses).
extraDependencyGroups = [ "hindsight" ];
environment = {
SIGNAL_HTTP_URL = "http://127.0.0.1:8080";
CODEX_HOME = "/var/lib/hermes/.codex";
@@ -44,14 +47,14 @@
toolsets = [ "all" ];
terminal.backend = "local";
# Self-hosted memory: pure SQLite in-process, no external services or
# API keys. db file lives under HERMES_HOME (= /var/lib/hermes/.hermes),
# which is on the persisted bind-mount.
memory.provider = "holographic";
plugins.hermes-memory-store = {
db_path = "/var/lib/hermes/.hermes/memory_store.db";
auto_extract = true;
default_trust = 0.5;
# Memory lives in a sibling hindsight-api process (see systemd unit
# below) backed by system postgres. Plugin talks HTTP to it locally.
memory.provider = "hindsight";
plugins.hermes-hindsight = {
mode = "local_external";
api_url = "http://127.0.0.1:8888";
bank_id = "hermes";
memory_mode = "hybrid";
};
};
};
@@ -80,6 +83,8 @@
systemd.tmpfiles.rules = [
"d /var/lib/hermes/.codex 0700 googlebot users -"
"C+ /var/lib/hermes/.codex/config.toml 0644 googlebot users - /etc/hermes-codex-config.toml"
"d /var/lib/hermes/hindsight 0700 googlebot users -"
"d /var/lib/hermes/postgresql 0750 postgres postgres -"
];
# signal-cli runs an HTTP JSON-RPC daemon on localhost; hermes-agent talks to
@@ -102,4 +107,103 @@
RestartSec = "5";
};
};
# ---------------------------------------------------------------------------
# Hindsight memory backend
#
# Architecture:
# hermes-agent --HTTP--> hindsight-api (port 8888) --asyncpg--> postgres
# hindsight-worker (background async retain/reflect)
#
# The api + worker run as googlebot with HOME=/var/lib/hermes so the
# `openai-codex` provider's hardcoded Path.home() / ".codex" / "auth.json"
# resolves to the persisted codex tokens.
# ---------------------------------------------------------------------------
services.postgresql = {
enable = true;
package = pkgs.postgresql_17;
extensions = ps: [ ps.pgvector ];
# Persist DB state on the /var/lib/hermes bind mount so the hindsight
# memory bank survives `nixos-rebuild switch` (which recreates the
# incus container and wipes its writable layer).
dataDir = "/var/lib/hermes/postgresql/17";
ensureDatabases = [ "hindsight" ];
ensureUsers = [{
name = "googlebot";
# Superuser so the hindsight-api alembic migrations can `CREATE EXTENSION`
# and own the schema. Acceptable here because postgres is local-only to
# the sandboxed workspace and only talks to hindsight-api over the unix
# socket.
ensureClauses.superuser = true;
}];
};
systemd.services.hindsight-api =
let
env = {
# Connection — postgres is on the local unix socket; sqlalchemy gets
# an asyncpg URL via the asyncpg+host=<socket-dir> trick.
HINDSIGHT_API_DATABASE_URL = "postgresql+asyncpg:///hindsight?host=/run/postgresql";
HINDSIGHT_API_HOST = "127.0.0.1";
HINDSIGHT_API_PORT = "8888";
# LLM + embeddings both ride codex OAuth — no separate keys.
HINDSIGHT_API_LLM_PROVIDER = "openai-codex";
HINDSIGHT_API_EMBEDDINGS_PROVIDER = "openai-codex";
# We did not install [local-ml] extras, so disable the reranker
# (default is "local" which requires sentence-transformers).
HINDSIGHT_API_RERANKER_PROVIDER = "none";
# HOME drives where the codex auth file is read from
# (CodexLLM/CodexOAuthEmbeddings: Path.home() / ".codex" / "auth.json").
HOME = "/var/lib/hermes";
};
in
{
description = "Hindsight memory API server";
wantedBy = [ "multi-user.target" ];
after = [ "postgresql.service" "network-online.target" ];
wants = [ "network-online.target" ];
requires = [ "postgresql.service" ];
before = [ "hermes-agent.service" ];
environment = env;
serviceConfig = {
Type = "simple";
User = "googlebot";
Group = "users";
ExecStart = "${pkgs.hindsight-api}/bin/hindsight-api";
Restart = "always";
RestartSec = "5";
WorkingDirectory = "/var/lib/hermes/hindsight";
};
};
systemd.services.hindsight-worker =
let
env = {
HINDSIGHT_API_DATABASE_URL = "postgresql+asyncpg:///hindsight?host=/run/postgresql";
HINDSIGHT_API_LLM_PROVIDER = "openai-codex";
HINDSIGHT_API_EMBEDDINGS_PROVIDER = "openai-codex";
HINDSIGHT_API_RERANKER_PROVIDER = "none";
HOME = "/var/lib/hermes";
};
in
{
description = "Hindsight background worker (async retain / reflect)";
wantedBy = [ "multi-user.target" ];
after = [ "hindsight-api.service" ];
requires = [ "hindsight-api.service" ];
environment = env;
serviceConfig = {
Type = "simple";
User = "googlebot";
Group = "users";
ExecStart = "${pkgs.hindsight-api}/bin/hindsight-worker";
Restart = "always";
RestartSec = "5";
WorkingDirectory = "/var/lib/hermes/hindsight";
};
};
}
+9
View File
@@ -52,4 +52,13 @@ in
qtmultimedia qtwayland qtwebengine qcoro;
inherit (prev) lib fetchFromGitLab pkg-config sdl3 libcec wayland;
};
# Hindsight agent-memory server. Built via uv2nix against the upstream
# workspace; uses hermes-agent's toolchain pin to avoid duplicating uv2nix.
hindsight-api = prev.callPackage ../pkgs/hindsight {
hindsight-src = inputs.hindsight-src;
uv2nix = inputs.hermes-agent.inputs.uv2nix;
pyproject-nix = inputs.hermes-agent.inputs.pyproject-nix;
pyproject-build-systems = inputs.hermes-agent.inputs.pyproject-build-systems;
};
}
+72
View File
@@ -0,0 +1,72 @@
{ lib
, callPackage
, python312
, stdenv
, makeWrapper
, hindsight-src
, uv2nix
, pyproject-nix
, pyproject-build-systems
}:
# Build the hindsight-api-slim venv from upstream's uv workspace. We pick
# `hindsight-api-slim` (not `hindsight-api`) so we skip the `[all]` extras
# (local-ml, embedded-db). With openai-codex provider for both LLM and
# embeddings, and system postgres as the store, those extras are unused weight.
let
workspace = uv2nix.lib.workspace.loadWorkspace {
workspaceRoot = hindsight-src;
};
overlay = workspace.mkPyprojectOverlay {
sourcePreference = "wheel";
};
pythonSet =
(callPackage pyproject-nix.build.packages {
python = python312;
}).overrideScope
(lib.composeManyExtensions [
pyproject-build-systems.overlays.default
overlay
]);
venv = pythonSet.mkVirtualEnv "hindsight-api-env" {
hindsight-api-slim = [ ];
};
in
stdenv.mkDerivation {
pname = "hindsight-api";
version = "0.7.2";
dontUnpack = true;
nativeBuildInputs = [ makeWrapper ];
installPhase = ''
runHook preInstall
mkdir -p $out/bin
# The venv ships hindsight-api / hindsight-worker / hindsight-admin /
# hindsight-local-mcp / alembic in $venv/bin. Link them out so callers
# don't have to know about the venv layout.
for bin in hindsight-api hindsight-worker hindsight-admin hindsight-local-mcp alembic; do
if [ -e ${venv}/bin/$bin ]; then
ln -s ${venv}/bin/$bin $out/bin/$bin
fi
done
runHook postInstall
'';
passthru = {
inherit venv pythonSet;
pythonEnv = venv;
};
meta = with lib; {
description = "Hindsight: agent memory with knowledge graph and tiered retrieval";
homepage = "https://github.com/vectorize-io/hindsight";
license = licenses.mit;
mainProgram = "hindsight-api";
platforms = platforms.linux;
};
}