Ir al contenido

Entity Model (Person / Project / Task)

Esta página aún no está disponible en tu idioma.

Full spec: 00-product-spec.md

YZOS crystallizes observation data into browsable, searchable entity profiles that can be supplied to upstream AI tools. YZOS abstracts these uniformly as Entities. The initial implementation covers three kinds:

Kind Description
person Contacts, yourself, unrecognized senders
project Code repositories, workstreams, products
task In-progress work items, to-dos, tasks an AI tool is actively executing

The main pages of the Tauri preview UI are browsing and review surfaces for these three entity kinds.

Autonomous discovery vs manual maintenance

Section titled “Autonomous discovery vs manual maintenance”

Entities come from two sources. Autonomous discovery is the default path; manual maintenance is an enhancement on top of it:

Source Trigger Example
Autonomous discovery Observation data arrives -> the entity engine extracts automatically A new sender appears in chat -> creates an unrecognized person; Claude Code opens example-project -> creates/updates a project; sustained AI tool use -> creates an in-progress task
Manual maintenance User names, merges, or edits entities in the Tauri UI Unrecognized “Code Morgan” -> user renames to “Morgan”; two duplicate projects get merged

The system must keep producing usable entities without depending on user action. User naming and corrections accelerate convergence, but they are not a precondition.

Entities are not written once and frozen. YZOS continuously updates them based on new observation data:

New observation -> entity signal extraction -> matches an existing entity?
|- yes -> update summary / last_seen / sightings / links / confidence
|- no -> create candidate -> accumulate evidence -> threshold reached -> promote to entity
|
Cron maintenance -> merge duplicates / archive stale entities / refresh summaries / fix links
|
Next observation round -> iteration continues (closed loop)

Specific self-iteration behaviors:

Behavior Description
Summary rewrite On each new sighting, the local model regenerates entity.summary incrementally (not fabricated from scratch)
Status transition Task in_progress -> completed (AI tool session ends and no follow-up activity); project active -> archived (30 days without activity)
Confidence adjustment Same sender appears 3 times -> confidence rises from 0.3 to 0.7; long-term lack of evidence -> confidence is lowered or the entity is merged
Auto merge Two projects point at the same repo_path -> cron auto-merges them; same voiceprint cluster -> linked to a person
Auto promotion An unrecognized person with more than 10 messages across 2 platforms -> a display_name suggestion is auto-generated (still flagged unrecognized, pending user confirmation)
Link refresh A person mentions example-project in a Lark chat -> a person-project link is auto-created
Contradiction correction New evidence conflicts with the existing summary -> flagged needs_review, cron triggers a summary rewrite

Manual actions (naming, merging, deleting) are written as override signals into entity_overrides. Overrides take priority over automatic inference, but they only lock the overridden field; other fields keep iterating automatically.

Every entity kind shares a base set of fields in PostgreSQL; kind-specific data goes into a JSONB column:

CREATE TABLE entities (
id TEXT PRIMARY KEY,
kind TEXT NOT NULL, -- person | project | task
display_name TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
summary TEXT NOT NULL DEFAULT '',
first_seen_at TIMESTAMPTZ,
last_seen_at TIMESTAMPTZ,
message_count INTEGER NOT NULL DEFAULT 0,
sighting_count INTEGER NOT NULL DEFAULT 0,
confidence REAL NOT NULL DEFAULT 0.0,
discovery_kind TEXT NOT NULL DEFAULT 'auto', -- auto | manual | merged
needs_review BOOLEAN NOT NULL DEFAULT FALSE,
tags TEXT[] NOT NULL DEFAULT '{}',
aliases TEXT[] NOT NULL DEFAULT '{}',
metadata JSONB NOT NULL DEFAULT '{}',
okf_path TEXT,
embedding vector(384),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_entities_kind ON entities (kind, last_seen_at DESC);
CREATE INDEX idx_entities_status ON entities (kind, status);
CREATE INDEX idx_entities_confidence ON entities (kind, confidence DESC);

When evidence is insufficient, autonomously discovered entities go into a candidate pool first, so weak signals do not pollute the main entity table:

CREATE TABLE entity_candidates (
id TEXT PRIMARY KEY,
kind TEXT NOT NULL,
hypothesized_name TEXT NOT NULL,
confidence REAL NOT NULL DEFAULT 0.0,
evidence_count INTEGER NOT NULL DEFAULT 0,
evidence JSONB NOT NULL DEFAULT '[]', -- [{source_kind, source_id, signal, at}]
promotion_threshold REAL NOT NULL DEFAULT 0.6,
status TEXT NOT NULL DEFAULT 'accumulating', -- accumulating | promoted | discarded
promoted_entity_id TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Promotion rules (default):

Kind Promotion condition
person Same platform_id appears 3 or more times, or appears across 2 different source_kind values
project Confirmed repo_path or AI tool project_path matches 2 or more times
task AI tool use sequence of 2 or more steps, or explicitly mentioned as a work item in chat/voice

Every automatic update leaves a record, for the review UI and for debugging:

CREATE TABLE entity_revisions (
id TEXT PRIMARY KEY,
entity_id TEXT NOT NULL REFERENCES entities(id),
revision_kind TEXT NOT NULL, -- summary_update | status_change | merge | link_add | confidence_change
old_value JSONB,
new_value JSONB NOT NULL,
trigger TEXT NOT NULL, -- triage | cron:entity_rollup | manual | reconcile
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE entity_overrides (
entity_id TEXT NOT NULL REFERENCES entities(id),
field TEXT NOT NULL, -- display_name | status | merge_into | ...
value JSONB NOT NULL,
set_by TEXT NOT NULL DEFAULT 'user',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (entity_id, field)
);

An overridden field is no longer touched by automatic iteration; every other field keeps updating itself.

Links between entities:

CREATE TABLE entity_links (
source_id TEXT NOT NULL REFERENCES entities(id),
target_id TEXT NOT NULL REFERENCES entities(id),
link_kind TEXT NOT NULL, -- works_on | involves | blocks | related | spawned_by
weight REAL NOT NULL DEFAULT 1.0,
evidence JSONB NOT NULL DEFAULT '{}',
PRIMARY KEY (source_id, target_id, link_kind)
);

Links between entities and the raw observation data that produced them:

CREATE TABLE entity_sightings (
id TEXT PRIMARY KEY,
entity_id TEXT NOT NULL REFERENCES entities(id),
source_kind TEXT NOT NULL, -- activity | chat | ai_tool | voice
source_id TEXT NOT NULL,
platform TEXT, -- wechat | telegram | lark | ghostty | claude-code ...
context_summary TEXT NOT NULL DEFAULT '',
seen_at TIMESTAMPTZ NOT NULL,
metadata JSONB NOT NULL DEFAULT '{}'
);

A person’s detail view surfaces their identity, activity, and communication data together.

Group status Description
You self The user themselves, unique
Contacts recognized Named and confirmed people
Unrecognized unrecognized Seen but not yet named, pending user confirmation or automatic inference
{
"id": "person-self",
"kind": "person",
"display_name": "Alex",
"status": "self",
"tags": ["@alexdev", "Nightowl", "AC"],
"message_count": 17,
"first_seen_at": "2026-06-11T14:45:00+04:00",
"last_seen_at": "2026-06-25T11:15:00+04:00",
"metadata": {
"avatar_letter": "A",
"voiceprint_status": "not_enrolled",
"platforms_seen": {
"wechat": 17,
"telegram": 3,
"lark": 5
},
"chat_accounts": [
{"platform": "telegram", "username": "nightowl_dev", "id": "1000000001"}
]
}
}
+-----------------------------------------------------------------+
| People - 381 recognized |
| [Search by name, alias, or account...] |
+---------------+---------------------------------------------------+
| You | [A] Alex You |
| * Alex OK | @alexdev Nightowl AC |
| | +--------+ +--------+ +--------+ |
| Contacts (3) | |Messages| |First | |Last | |
| * Jordan | | 17 | |seen | |seen | |
| * Sam | | | |Jun 11 | |2d ago | |
| * Robin | +--------+ +--------+ +--------+ |
| | |
| Unrecognized | Where YZOS has seen them |
| (377) | WeChat ################ 17 |
| * Taylor | |
| * Code Morgan| Activity sessions (7) |
| * ... | +-------------------------------------------+ |
| | | WeChat, Telegram, Ghostty, Chrome, Lark | |
| | | Jun 25 11:15 - last seen 2 days ago > | |
| | +-------------------------------------------+ |
| | | WeChat, Telegram, Ghostty, Chrome, QQ > | |
| | +-------------------------------------------+ |
| | |
| | Voiceprint Not enrolled [Record 10s] |
| | Record a short sample so YZOS can tell you |
| | apart from others on a shared microphone |
| | |
| | Chat accounts |
| | Telegram nightowl_dev (1000000001) |
+---------------+---------------------------------------------------+
Source Extraction method
Chat messages sender_id / sender_name -> create or link an entity
Activity OCR Speaker name shown in a chat window
Voice diarization Speaker cluster -> matched against the voiceprint library or flagged unrecognized
Meeting transcripts Participant names
Manual naming by user unrecognized -> confirmed -> recognized
CREATE TABLE voiceprints (
entity_id TEXT PRIMARY KEY REFERENCES entities(id),
embedding vector(256) NOT NULL,
sample_path TEXT NOT NULL,
enrolled_at TIMESTAMPTZ NOT NULL,
duration_ms INTEGER NOT NULL
);

Users enroll their own voiceprint through “Record 10 seconds” in the Tauri UI. In shared-microphone office settings, YZOS uses the voiceprint to distinguish “you” from other speakers, avoiding misattributing face-to-face conversations to you.


Project entities are discovered automatically from repository paths, window titles, AI tool sessions, and chat content.

Source Example
Git repository path /Users/you/code/example-project -> example-project
AI tool session Claude Code project path
Window title / OCR “Internal Dashboard - Admin Panel”
Chat mention A Lark group discusses “internal-dashboard DNS”
Manual by user Linking a directory in settings
{
"id": "project-example-project",
"kind": "project",
"display_name": "Example Project",
"status": "active",
"summary": "A unified example service, with recent work on SAML/OIDC auth integration and production incident recovery.",
"first_seen_at": "2026-05-01T00:00:00+04:00",
"last_seen_at": "2026-06-27T18:00:00+04:00",
"tags": ["java", "k8s", "auth"],
"metadata": {
"repo_path": "/Users/you/code/example-project",
"project_line": "internal-tools",
"platforms_seen": {
"ghostty": 45,
"google_chrome": 30,
"claude-code": 20
},
"ai_tools_active": ["claude-code"],
"related_people": ["person-jordan", "person-robin"],
"open_tasks_count": 3
}
}
+-----------------------------------------------------------------+
| Projects - 24 recognized |
+---------------+---------------------------------------------------+
| Active (8) | Example Project |
| * EP OK | internal-tools project line |
| * internal- | +--------+ +--------+ +--------+ |
| dashboard | |Active | |AI tool | |Open | |
| * billing- | |7 days | |Claude | |tasks: 3| |
| service | +--------+ +--------+ +--------+ |
| | |
| Recent (12) | Summary |
| Archived (4) | SAML ACS URL fix, OIDC compatibility, production |
| | database recovery |
| | |
| | Where YZOS has seen it |
| | Ghostty ######### 45h |
| | Chrome ###### 30h |
| | Claude Code #### 20h |
| | |
| | Related people |
| | Jordan (Lark) * Robin (WeChat) |
| | |
| | Open tasks (3) |
| | * SAML ACS URL fix claude-code in_progress >|
| | * DB migration plan pending > |
| | |
| | Related knowledge (5) |
| | * SAML ACS URL missing base_url prefix > |
+---------------+---------------------------------------------------+

Task entities are recognized from AI tool execution, terminal commands, chat scheduling, and voice discussions.

Source Example
AI tool use Claude Code Edit src/auth/saml.py
Autonomous AI execution Codex continuously running tests
Chat scheduling Lark: “let’s push the DB migration tomorrow”
Voice discussion “I’ll fix the certificate inspection logic this afternoon”
Activity inference Same project, same activity, 3 consecutive days
status Description
in_progress In progress (AI tool active / user actively working)
pending Not yet started (a plan extracted from chat/voice)
completed Completed
blocked Blocked
stale No activity for a long time, pending archival
{
"id": "task-saml-acs-fix",
"kind": "task",
"display_name": "SAML ACS URL fix",
"status": "in_progress",
"summary": "Fix the SAML ACS URL missing its base_url prefix, and sync the use_absolute_acs_url flag on the frontend.",
"first_seen_at": "2026-06-27T14:30:00+04:00",
"last_seen_at": "2026-06-27T15:45:00+04:00",
"tags": ["saml", "auth"],
"metadata": {
"project_id": "project-example-project",
"executor": "claude-code",
"executor_status": "autonomous",
"involved_people": [],
"tool_uses": [
{"tool": "Edit", "target": "src/auth/saml.py"},
{"tool": "Bash", "command": "pytest tests/auth/"}
],
"source": "ai_tool_session"
}
}
+-----------------------------------------------------------------+
| Tasks - 12 in progress - 5 pending |
+---------------+---------------------------------------------------+
| In progress | SAML ACS URL fix |
| (12) | Example Project - Claude Code - in_progress |
| * SAML OK | +--------+ +--------+ +--------+ |
| * DNS monitor| |Started | |Elapsed | |Tool use| |
| * DB migrate | |Jun 27 | |1h 15m | | 8x | |
| | +--------+ +--------+ +--------+ |
| Pending (5) | |
| Completed | Summary |
| (today: 3) | Fix the SAML ACS URL missing its base_url |
| | prefix ... |
| | |
| | Executor |
| | Claude Code (running autonomously, user has |
| | switched to another app) |
| | |
| | Tool use timeline |
| | 14:32 Edit src/auth/saml.py |
| | 14:45 Bash pytest tests/auth/ -> passed |
| | |
| | Related project -> Example Project |
| | Related knowledge -> SAML ACS URL prefix issue |
+---------------+---------------------------------------------------+

Entity engine (autonomous discovery + self-iteration)

Section titled “Entity engine (autonomous discovery + self-iteration)”

A dedicated module, entity_engine, runs in two phases: Triage and Cron.

After every observation session ends, the following runs synchronously:

1. Signal Extractor - extracts entity signals from OCR/chat/AI logs/voice
person: {platform, platform_id, display_name?, voice_cluster?}
project: {repo_path?, window_title?, ai_project_path?, keywords[]}
task: {action_verb, target_file?, ai_tool_uses[], chat_intent?}
2. Entity Matcher - matches against existing entities/candidates (embedding + rules)
similarity > 0.85 -> same entity
0.6 - 0.85 -> accumulate in candidate pool
< 0.6 -> new candidate
3. Entity Updater - updates the formal entity or the candidate
- UPSERT sighting
- Incrementally rewrite summary (local model, input = old summary + new evidence)
- Refresh confidence, last_seen, links
- Check entity_overrides, skip fields locked by manual override
4. OKF Writer - syncs to entities/{kind}/{id}.md
5. Indexer - updates the PG embedding
Job Schedule Self-maintenance behavior
entity_rollup Daily at 02:00 Full rewrite of every entity summary (aggregated from recent sightings)
entity_merge Weekly Auto-merges high-confidence duplicate entities (same repo_path, same voiceprint, same platform_id)
entity_promote Hourly Promotes candidates that have reached their threshold to formal entities
entity_demote Daily Demotes, archives, or discards formal entities with no evidence for a long time
entity_archive Daily Archives tasks that are completed or projects with 30 days of no activity
entity_link_refresh Daily Refreshes person-project-task links from co-occurrence analysis
entity_reconcile Daily Reconciles OKF entity profiles against PostgreSQL
entity_review_scan Daily Flags contradictory or low-confidence entities as needs_review, highlighted in the Tauri UI
flowchart TD
    O[Observe] --> T[Triage + Entity Engine]
    T --> M{Match?}
    M -->|Existing entity| U[Incremental update: summary/links/confidence]
    M -->|Candidate| C[entity_candidates accumulates evidence]
    C -->|Threshold reached| P[Promote to entities]
    M -->|New signal| C
    U --> OKF[OKF + PG Index]
    P --> OKF
    OKF --> S[MCP supply to upstream AI]
    OKF --> UI[Tauri preview]
    CRON[Cron self-maintenance] --> U
    CRON --> MERGE[Auto merge/archive/promote]
    MERGE --> OKF
    USER[User naming/correction] --> OV[entity_overrides]
    OV -.->|Locks field| U
    O --> CRON
flowchart TD
    A[Observe raw data] --> B[Signal Extractor]
    B --> C{Matches existing entity?}
    C -->|Yes| D[Incremental update + sighting]
    C -->|Candidate| E[Accumulate evidence]
    C -->|No| E
    E --> F{Promotion threshold reached?}
    F -->|Yes| G[Create formal entity]
    F -->|No| H[Stays in candidate pool]
    D --> I[Rewrite summary + refresh links]
    G --> I
    I --> J[OKF profile + PG embedding]
    J --> K[Tauri preview / MCP supply]
    L[Cron self-maintenance] --> I
    L --> M[Merge/archive/promote/reconcile]

An upstream AI (Claude Code) asks “what’s the current status of Example Project”:

-> yzos_entity_get(id="project-example-project")
<- {summary, open_tasks: [task-saml-acs-fix, ...], related_people: [...]}
-> yzos_entity_search(kind="task", project="example-project", status="in_progress")
<- [{display_name: "SAML ACS URL fix", executor: "claude-code", ...}]

An upstream AI asks “who did I talk to today”:

-> yzos_entity_list(kind="person", since="today")
<- [{display_name: "Jordan", message_count: 12, platforms: ["wechat"]}, ...]