feat: entity enrichment — metadata, relationships, and self-entity (#470)
## Summary
Enriches the entity system with three interconnected features:
### 1. Entity Metadata
Wire up the existing `metadata` JSON column end-to-end — it existed in
the schema but nothing populated it.
- **Curator** now extracts `description` and `role` metadata for
entities
- **Metadata merge on dedup**: when `create()` finds an existing entity,
incoming metadata fills gaps while existing non-empty values win (same
intuition as alias dedup)
- **CLI**: `--metadata` flag on `lore entity add`, new `lore entity
edit` subcommand
- **Dashboard**: structured display (Role, Description, Notes) + edit
form replacing raw `<pre>` JSON
### 2. Entity Relationships
New `entity_relations` table (migration v28) for directed
entity-to-entity connections.
- **Relation types**: friend, colleague, manager, report, collaborator,
client, mentor, partner
- **Curator** extracts relationships from conversation ("Melkey and I
are friends" → relation)
- **CLI**: `lore entity relation add/rm`, relationships shown in `lore
entity show`
- **Dashboard**: relationships section on entity detail page
- Relations cleaned up on entity delete/merge
### 3. Self-Entity
New `entity_type = 'self'` (no extra column needed) identifies the Lore
user as an entity.
- **Auto-detected** from `git config user.name/email`
- **Configurable** via `.lore.json` `user` section (name, email,
aliases, metadata)
- **Anchors relationships**: "Melkey is my friend" has a concrete
self-entity to point to
- **Prompt injection**: self entity marked as "you (the user)", related
entities get `[friend]` tags
### 4. Hybrid Entity Injection Policy
- **Agent system prompt**: inject all entities if ≤30 (configurable via
`knowledge.maxEntityInject`), otherwise self + self's relations +
relevance-ranked remainder
- **Curator prompt**: always gets the full entity list (needs it for
grounding/dedup)
### 5. Type-Based Scoping Defaults
- `self`/`person`/`org`/`service`/`tool` → cross-project by default
(user-level)
- `repo`/`infra` → project-scoped by default
- Explicit `crossProject` param still overrides
## Files Changed (12)
| File | Change |
|------|--------|
| `packages/core/src/db.ts` | Migration v28: `entity_relations` table +
recovery block |
| `packages/core/src/entities.ts` | Types, helpers, self-entity,
metadata merge, relations CRUD, injection, prompt formatting (+423
lines) |
| `packages/core/src/curator.ts` | `DetectedEntity.metadata`,
`DetectedRelation`, `filterRelations()`, `applyOps()` |
| `packages/core/src/prompt.ts` | Curator prompt: metadata/relation
schema, entity grounding instructions |
| `packages/core/src/config.ts` | `user` section +
`knowledge.maxEntityInject` |
| `packages/core/src/git.ts` | `getGitUser()` — reads git config
user.name/email |
| `packages/core/src/index.ts` | Export `getGitUser`,
`clearGitUserCache` |
| `packages/gateway/src/cli/entity.ts` | `--metadata` on add, `edit`
subcommand, `relation add/rm` |
| `packages/gateway/src/ui.ts` | Structured metadata display + edit
form, relationships section |
| `packages/core/test/entities.test.ts` | **NEW** — 47 tests covering
all new functionality |
| `packages/core/test/db.test.ts` | Schema version 27 → 28 |
| `.lore.md` | Updated knowledge entries |
## Testing
- **1891 tests pass, 0 failures** across 70 test files
- **All 4 packages typecheck clean**
- 47 new tests covering metadata CRUD, mergeMetadata, cross_project
defaults, self-entity, relations CRUD, formatForPrompt,
entitiesForSession, curator integration, merge with relations
Closes #459 (entity metadata), related to #462 (entity dedup). B
Burak Yigit Kaya committed
668457f863f787dfbd3e6101e021ffbd363bdf2d
Parent: 9afaaae
Committed by GitHub <noreply@github.com>
on 5/24/2026, 6:36:49 PM