# Halofy: one identity model for agent memory over MCP and HTTP

> Halofy is a TypeScript kernel that puts agent identity, namespace access, provenance and erasure behind every memory read and write. The governance is the product; the retrieval engine stays swappable underneath.

**halofyai/halofy** — Halofy is the open access and governance layer for AI agents across your organization. Identity, policy, provenance, audit, and signed erasure.

- Repository: https://github.com/halofyai/halofy
- Website: https://halofy.ai
- Stars: 335 · Forks: 24
- Language: TypeScript
- License: AGPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/halofyai-halofy

## Identity comes from the credential, never the request body

Halofy is a TypeScript kernel that sits between an organization's knowledge and the agents reading it, and the first thing it settles is who the caller is. Namespace, actor, role and source scope are pulled out of the credential. A request body cannot assert them, and the MCP tool schemas carry no field for a caller to fill in. Keys are minted from the CLI, where a namespace path, a principal and a role are three separate arguments:

```bash
cd kernel
npx tsx src/cli.ts keygen org/support/agent-1 user:dana owner
HALOMEM_API_KEY=hm_... npm run mcp
```

That generated key is the entire identity. Hand it to `npm run mcp` in the environment variable `HALOMEM_API_KEY` and the server resolves `org/support/agent-1`, `user:dana` and the `owner` role on every call, over MCP or over HTTP, with the same ACL and role decisions whichever door an agent arrives through. The repository layout reflects how much of this project is policy: GOVERNANCE.md, MAINTAINERS.md, LICENSING.md, SECURITY.md, TRADEMARK.md and a .gitleaks.toml sit beside a single `kernel/` directory where the code lives.

## A caller in org/support sees org, not org/sales

The core namespace rule is small enough to hold in your head. A caller in namespace N sees rows belonging to N or to an exact `/`-split ancestor of N, and nothing else. The project's own worked example, for a caller at org/support/agent-1, makes the shape visible:

```text
caller: org/support/agent-1

org                          visible     ancestor
org/support                  visible     ancestor
org/support/agent-1          visible     self
org/support/agent-2          hidden      sibling
org/support/agent-1/scratch  hidden      descendant
org/sales                    hidden      sibling
```

A support agent cannot read a sibling agent's namespace, and it cannot see its own scratch subtree either. Descendants stay invisible until an explicit, audited administration path runs a subtree operation. The query layer performs the exact ancestor matching, and retrieval drivers are handed an already-scoped `ScopedView` instead of being trusted to reimplement the rule. A retriever can return references only. It has no route to write and no route to the audit or storage modules.

## The demo boots on embedded PGlite with no key and no network

Everything runs without an API key, a database server, a model download or a network call. Embedded PGlite is the zero-setup local default, and the shipped demo pins a policy, assembles a working set, writes, runs hybrid search, injects an L3 context fault, audits, imports, shows fragmentation, and erases a customer behind a signed certificate:

```bash
git clone https://github.com/halofyai/halofy.git
cd halofy/kernel
npm ci
npm run demo
```

The boot line names the substitutes in play, `booted: embedder=hash(dim=256) llm=stub`, and the last stage prints `verifyCertificate === true` followed by zero matching facts from `mem_search`. The same hermetic lane backs the test suite, with a deterministic `StubLlm`, a `HashEmbedder` and zero network access:

```bash
npm test
npx tsx src/cli.ts conformance baseline
```

2,678 tests across 205 files and 6 out of 6 driver-conformance checks is the figure quoted, with the caveat that timings and generated identifiers vary by machine while the behavior does not. Mind the path change between snippets: the quickstart says `cd halofy/kernel` straight after cloning, later commands say `cd kernel`.

To get the API and the control room instead:

```bash
cd kernel
npm run serve
```

Then open `http://localhost:8787/console/login`. The console is described as frameworkless and covers access, teams, sources, policies, conflicts, retrieval quality, audit, alerts, skills, connected apps and export, though the README does not walk through individual panels.

## Eight mem_ verbs and four connectors, one governed write path

An agent talks to `mem_write`, `mem_read`, `mem_search`, `mem_assemble`, `mem_fault`, `mem_stats` and `mem_forget`, plus policy, sharing, pinning, export and manifest operations. `mem_assemble` is the one that matters most to an agent runtime, because it returns an assembled working set instead of a bag of hits. `mem_fault` is stranger: it deliberately pages missing context in from a lower tier, and the demo reports `fault: hit=true source=L3 injected=2`. Read that as a fault-injection tool for finding out what an agent does when the context it needs is not in front of it, not as a repair command.

Content enters through four public connectors: filesystem, Postgres, Obsidian, and manual CSV import. All four feed the same governed write path, so an Obsidian vault and a CSV dump land in the same provenance, entity resolution and dedupe machinery instead of drifting into a side index that nobody audits.

## A correction closes a validity interval instead of overwriting the fact

When a fact turns out to be wrong, Halofy closes the prior fact's validity interval and links the replacement. History is not overwritten, so the stale value stays readable and the chain of supersedence stays walkable. The rest of the lifecycle follows from that choice: provenance on every change, entity resolution, exact and semantic dedupe, append-only audit.

Audit coverage runs wider than success. Success, denial, miss, brownout and error paths all append an event, so a policy that refuses a read leaves the same kind of trace as a read that lands. Erasure rides on the same structure. `mem.forget` erases a customer and mints a signed certificate, and the demo prints the certificate prefix with a verification result before showing `mem_search` surfacing 0 matching facts. The certificate is the part that carries weight in a compliance conversation, because the claim can be checked without trusting the database that lost the data. The known partial controls and adversarial cases live in `docs/security/threat-model.md`, and that file is the one to read before trusting the boundary with anything sensitive.

## Postgres stays the authority while retrieval engines stay swappable

Everything that has to survive lives in Postgres: context, embeddings, policy, provenance, tombstones and audit share one store. pgvector carries operational context and a cold tier of encrypted, Git-versioned knowledge sits behind it. PGlite embeds the same model for local development and tests, which is the reason the offline demo and a Postgres deployment are meant to behave alike.

That split is the argument against the usual arrangement. The common pattern for agent memory is a vector store plus one API key per agent, which leaves access control scattered through application code and leaves erasure as a delete you hope finished. Halofy moves the decision into the query layer and keeps retrieval replaceable: engines plug in through an ACL-scoped, read-only driver interface, and the conformance command exists to check that a driver behaves. On the openness side, the standalone build asks for no licence key, no edition flag, no activation and no entitlement check, the public `QuotaPort` defaults to `UNMETERED`, and there is no telemetry or phone-home. Capacity control is left to the operator through policy rate limits and model-budget brownout.

## Hosting it yourself, licensing it, and the one case to skip

Three costs to weigh first. Hosting is yours: `docs/self-hosting.md` is where Postgres, generated keys and Docker Compose are covered, and the control room listens on port 8787. Licensing needs a decision rather than a guess, since the repository is AGPL-3.0 and also ships LICENSE-APACHE-2.0 next to LICENSING.md and OPEN-SOURCE-SCOPE.md, which is the arrangement to read before the kernel ends up inside a service you do not publish. Versioning gives you nothing to pin, because the repository has no GitHub releases; the last push was on 2026-09-22.

The wrong-tool case is narrow but real. For a personal note store with no organization behind it, a namespace ACL, an append-only audit and a signed erasure certificate are all cost with no buyer. And the local default embedder hashes text into 256 dimensions, so what a query returns on your laptop is a property of the test lane rather than evidence about production retrieval quality.

## Conclusion

Adopt Halofy when several agents and operators must share one governed corpus and someone will ask you to prove an erasure afterwards. Skip it for a single user note store, where the namespace ACL and the audit trail buy nothing. Verify two things first: the known partial controls listed in docs/security/threat-model.md against the boundary you actually need, and the AGPL-3.0 terms in LICENSING.md against the way you plan to ship.

## FAQ

### What does Halofy actually do for AI agents?

Halofy is a TypeScript governance layer that sits between organizational knowledge and the agents using it. It resolves identity, enforces access, governs every change, records each outcome in an append-only audit, and makes erasure independently verifiable through a signed certificate.

### Does Halofy need an API key or a model download to run?

No. The demo boots the real kernel on embedded PGlite with no API key, no database server, no model download and no network call. The test lane substitutes a deterministic StubLlm and a HashEmbedder and runs with zero network access.

### Can Halofy be self-hosted with Postgres and Docker Compose?

Yes, the project points to its self-hosting guide for a durable deployment with Postgres, generated keys and Docker Compose. The standalone build itself asks for no licence key, no activation and no entitlement check, and the public QuotaPort defaults to UNMETERED.

### How does Halofy prove that a customer's data was erased?

The mem.forget operation erases the customer and mints a signed certificate, which the demo verifies and prints a prefix of. After erasure, mem_search surfaces 0 matching facts, so the claim can be checked without trusting the store that held the record.

### What can a Halofy agent see in another namespace?

A caller sees its own namespace and exact slash-separated ancestors of it, and nothing more. Siblings and descendants stay hidden unless an explicit, audited administration path performs a subtree operation.

### Is Halofy released under a permissive open source license?

The repository is licensed AGPL-3.0 and also ships LICENSE-APACHE-2.0, with LICENSING.md and OPEN-SOURCE-SCOPE.md at the top level. Read those files before embedding the kernel in a service you do not publish.

## Sources

- [halofyai/halofy on GitHub](https://github.com/halofyai/halofy)
- [Issues](https://github.com/halofyai/halofy/issues)
- [License: AGPL-3.0](https://github.com/halofyai/halofy/blob/main/LICENSE)
- [Project website](https://halofy.ai)
- [README](https://github.com/halofyai/halofy/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/halofyai-halofy
