What if I told you that every Mac since 2022 ships a pair of daemons whose only purpose in life is to build a graph about you and the people around you: who you are, who you know, how those people are related to you and to each other, how you communicate with them, where you go, with whom, what you do and when. This graph is built on device by cross-referencing pretty much everything on the machine: Contacts, Calendar, Photos, Messages, Mail, location, Screen Time and a long tail of behavioral signals. And, more importantly, it is held as a queryable store that LLMs retrieve from (allegedly). Would you believe me?
Well, that's what is happening, and interestingly enough, there is little documentation of how this whole mechanism works on your Mac. The closest thing to an official description is the man page (man 8 knowledgeconstructiond), and this is all you get:
NAME
knowledgeconstructiond – A daemon that analyzes content on the
device to build a general purpose knowledge graph.
DESCRIPTION
knowledgeconstructiond analyzes the content on this device to help
build a knowledge graph representing the device and the user. It
works together with intelligenceplatformd, performing some of the
heavy processing tasks, to generate the knowledge graph.Previous work: To be fair, Apple's own researchers did publish a paper on the techniques behind this graph construction, back in 2023. But there is next to nothing on how it is integrated into macOS: which versions run it, and the exact list of what is collected and inferred. And not a word about the "kinship" inference discussed below. Also, we personally ran into it while doing some security research on the Apple Intelligence bundle in macOS 26 in August 2026; but a few months before, Nic Lydon came across the same database and wrote it up in I Built a Personal Knowledge Graph. Apple Had Already Built One on My Laptop. And even more recently, a forensics tool went looking on the phone: in September 2026, Alexis Brignoni taught iLEAPP to read the same store on iOS, where graph.db and the ontology.db that decodes its predicate codes sit under /private/var/mobile/Library/IntelligencePlatform; he writes it up in Reading the iPhone Knowledge Graph, and Checking Its Work.
But we go a bit deeper.
This blog post is an account of some analysis work we carried out on what the knowledge graph actually does, so that you (the user) can get a better understanding of how this mechanism works, and some clarity on what the graph holds about you and your family and friends. Everything in it was collected on macOS 26 (26.6.2 at the time of writing).
To this end, we open-source a local dashboard (iKnow) you can use to read the content of your personal knowledge graph on your Mac.
Finally, we derail a bit and look into what we do best: weaponizing and exploiting. We run a thought experiment (one that applies to any such personalized system) and show what happens if such a knowledge base ends up in the wrong hands, and how a "privacy single point of failure" can be exploited to threaten you in ways you may not have considered before (when combined with an abliterated LLM).
What's in the personal knowledge graph?
The two daemons keep their work in ~/Library/IntelligencePlatform, a directory of SQLite databases (fifty-one databases) stored in plaintext but located in a zone protected by TCC Full Disk Access.
Likely, the most interesting is graph.db. It is a triple store written in a vocabulary of 181 entity classes and 278 predicates: every row is a subject, a predicate and an object. The subject is an entity (a person, an app, an event); the object is either a plain value (a name, a handle, a date) or another entity, which is where the graph gets its edges. The predicate is the interesting part: it says what kind of relationship the system believes holds between the two.
an edge, and the rows it is stored as
One edge of the graph (synthetic data): a person and the organization the store holds as their employer. PS500 is the id predicate.json gives employer, and its range is not an organization but a relationship type — so one edge is two rows sharing a relationshipId, one naming the kind of relationship and one pointing at the other entity. The forty-six relationship type classes in the table below exist to carry exactly that, which is what lets an edge hold a confidence of its own and be retracted later.
Most of what the two daemons do is populate those predicates, and the tables kept beside them, from everything the OS will let them read. Into the graph go Contacts; Photos (faces); Calendar (titles and attendees); Family Sharing (including the age of every member); the Medical ID emergency contact in Health; events and contacts Siri Suggestions finds in Mail and Messages; people donated by apps through App Intents; and installed apps. Beside it, in tables of their own, sit who appears with whom in your photos; the communication log (who, when, which app, which direction; no content), which also pulls from your other devices; location and movement; and a long tail of device signals (screen locked, Wi-Fi, Bluetooth, charging, ambient light, and a stream named ContextualUnderstanding.PhysicalSocial whose record format lists people by name, phone and email, each with a start and an end time; it reads like a log of who was physically around you, though we never saw it filled in).
What is inferred
The complete list of the 181 entity classes:
the 181 entity classes in class.json
Every class the shipped ontology declares, grouped rather than left in file order: the core types, then people, attributes, places and events, then the activity block, and last the forty-six relationship types, which are not things at all — each one reifies an edge so that the edge can carry facets of its own, a confidence among them. The ids and labels are Apple's; the grouping is ours. intValue runs 1 to 185 with four numbers missing — 18, 54, 169, 181 — and nothing on the disk says what they were.
Fifty-seven of the 181 describe an activity: sleeping, exercising, mindfulness, going to bed, commute, dining, most of them with a matching type class beside them, so nearly a third of the vocabulary went on what you are doing rather than on who or where you are. That said, it is not clear that every class is actually used; some may be placeholders that are declared and never filled. In the table, we flag as implemented the classes for which we could locate a mechanism that might be responsible for the class, but those are to be taken as inference work rather than ground truth.
And this is the complete list of predicates (same disclaimer applies):
the 278 predicates in predicate.json
Every predicate the shipped ontology declares. The first column is the id as graph.db stores it; the last says how a value gets there: copied from a source, joined from another record, derived by a rule, shipped by Apple as world knowledge, or produced by a model (in bold). Seven we could not establish, and the table says so rather than guessing. The ids and labels are Apple's; the plain-language readings are ours.
How it is inferred
The methods run the whole range. Most of the vocabulary is filled by plain copying (a name from Contacts, an attendee from Calendar) and rules over the copies; the interesting rows come from models: a pair of XGBoost classifiers decides who is family from 144 mostly behavioral features, two embedding models are one of ten signals the system uses to decide when two records are the same person, twelve analyzers in Photos score partner, parent, child, coworker and friend from who appears in your pictures with you, on which trips and holidays, and Apple's on-device LLM reads your messages to put a name and a relationship on a face (if Apple Intelligence is active).
Whatever the method, every row lands in the graph with a confidence attached, a number between 0 and 1.
The family scores live apart. Two CoreML models ship next to the ontology, EntityTagging_Family.mlmodelc and EntityTagging_FamilyAndFriends.mlmodelc: binary XGBoost classifiers that take 144 features and return a class and a probability over it. Their scores do not go into the triple store but into a table of their own (entityTagging.db, one row per person, seventeen relationship columns from family to mother to coworker, recomputed every day), which is what the iKnow scorecard further down reads. Only two of those seventeen columns have a shipped model behind them; what fills the other fifteen, and how any of these probabilities would become a confidence in the graph, we could not trace.
The feature names are in each model's metadata.json, in plain text. They are the clearest statement of what this system is that I have found anywhere. All 144:
the 144 features in metadata.json
Every input EntityTagging_Family.mlmodelc reads, in the order its metadata.json declares them. EntityTagging_FamilyAndFriends reads the same 144 in the same order, and every one is a number. The groups are the schema's own three blocks: twenty on who the person is, forty on when and how you communicate with them, eighty-four on the photographs you both appear in. Two of the twenty, photosPersonAge and photosAgeDifferenceCategory, are read from Photos too. The names are Apple's; the group labels are ours.
The identity group is the tidy story: same surname, same home address, an iCloud Family flag — and it is the small half. The bulk of the model is the other two: who you message and who appears in your photographs, conditioned on the day of the week and the time of day, and then on both at once. photosPersonPosteriorProbabilityGivenSaturdayNight is a shipped feature name in a shipped classifier whose job is deciding whether someone is family.
Deleting something does not delete it everywhere.
The live graph forgets. Delete a contact and nothing re-derives them; the next run replaces the table wholesale.
But the store keeps a second table, expired_stable_graph, beside the live one. The retracted row moves there and keeps its confidence and its sources. How long it stays there is not clear from what we could see. It seems to go after about 48 hours (the store keeps a prune watermark, and a recent snapshot of the table reached back no further than that); but on my own Mac, I could still read very old records in it.
And a conclusion can outlive the evidence for it. On my Mac, the scorecard still scored two people the graph had dropped the day before, both of them known to it only from a calendar invitation. Well, if you want your partner not to discover some contacts you might have deleted and their "closeness" to you, better to drop some rows from expired_stable_graph too (unfortunately, you have to do it manually). But I am sure you have nothing to hide (just joking).
Look into your own data
Is any of this sensitive? We'll leave that to you, since "sensitive" means different things to different people (though I think you have plenty to choose from here). However, the thing is, none of it lives in isolation. It is built to be joined and correlated; the nodes are there to be linked:
a personal knowledge graph (synthetic data)
me · the owner of this Mac · 1a group the store holds as an entity · 1family, as scored · 7scored close to me · 9employer · 4group chat · 6known, not scored close · 61membership of a group chata calendar event both attendedan employment statementnamed by the stored groupa closeness score above the cut · nobody typed it
How to read this
Every node is a row in the store, and the record under it is what the store holds. Size is how many rows name it; shape is what kind of thing it is; the one node in accent is you, and a ring marks the four the store scores as family. A dashed line is a conclusion nobody typed.
Click a node — or reach the graph with Tab, walk it with the arrow keys and press Enter — and its record replaces these notes.
Click a node and the record under the graph is what the store holds on it (the rows, not a summary of them). The sixty-one faint ones are the part nobody expects: people the store knows and has not placed, in it because they wrote to you once, or because they were on somebody else's invitation.
The most important point, though, is that this is not only about you (the person using the Mac). The people around you are in it too: your family, your friends, "anyone" you have talked to through your device. None of them was asked, and the store links them to you and, through the events and groups they share, to each other. A relationship is intelligence one level above the rows it was inferred from. For instance, by correlating across my own store, I (well, an LLM working for me) could easily work out the following:
- That there is a child in the household, and roughly how old. The family-member types and a family circle give the household. The scorecard's child and son/daughter columns give the child's place in it. Beside it sits an age, copied from Family Sharing; and dates of birth in the store can carry the system's own word imputed, though what the system means by it is not clear to us.
- Which daycare the child goes to, and both of the numbers that reach it. Copied off contact cards. Note what is not there: the calendar has no school-run event, so the store holds the institution and its lines but not the hour the child is dropped off. That is still enough to call a parent from a number their phone already trusts.
- Where the family will be, on which days, between which hours. One calendar event, a place, two stored time slots and a title that names the family (so the guest list is in the string even where the attendee rows are empty).
- Which of the family will be there. The scorecard names the ones scored as family, a household entity holds them together, and a Family Sharing circle says which of them are in the same family group.
- And, in the same file, what is installed on the machine, down to the password manager.
It is easy to see how this could be weaponized if this single point of failure for your privacy ends up in the wrong hands. We play that (hypothetical) scenario out in a second write-up. The good thing is that this knowledge is meant to stay local on your machine, protected by the Full Disk Access permission; although it can be consumed by other services (but it is not entirely clear to us how and what can be accessed).
The reality is that the amount of information in this store is really something else: every time we dig into what the daemons infer, and how, a few new lines of investigation open up. Whatever you would rather no one knew about you or your family may well be in there somewhere, and we think you have the right to know whether it is. What you get instead: no documentation, no way to inspect the store and no general way to correct an inference that is wrong.
So we give you two tools. The first is iKnow, a local dashboard for browsing your own graph without anything leaving your Mac (the next section walks through it). The second is for going deeper. The iKnow repository ships a manual for your own agent that tells it where the databases are and how to read them, so it can go looking for whatever you are after. (Please point a self-hosted model at it, not a cloud one.)
iKnow
We designed iKnow as a web dashboard implemented in the Python standard library; no npm and no CDN.
It is meant to be run directly on your Mac, where the databases are stored. When executed, it binds 127.0.0.1, locates the databases in your file system (granted the necessary permissions), opens them read-only, collects the info on the fly and represents it on a dashboard. Nothing is written and nothing is logged; values go from the stores, over loopback, into a browser tab; it can be run air-gapped if you want.
We have tested it on macOS 26.6.2 and 26.7.1, and, only partially, on 27.0.1.
iKnow has a dozen pages.
Start here
What your Mac knows. The landing page: the graph of people around you. Below it come the faces in your photos, your family, your handles, your correspondents and where you will be next.
Its graph is the same household as the one at the top of this post, this time drawn by the tool's own renderer:
the landing page
The first screen. The white node marked (Me) is the owner of the Mac; the rest are the people, employers and group chats the store links to it, colored by what it says each one is. Orange is family, as scored. Blue is a closeness score above the cut. The faded names around the edges are people the store knows and has not placed.
Nothing here is summarized that is not in the record: every node is a row, and clicking one shows you the row (which is what the graph at the top of this post does too).
The graph is the overview, and an overview is easy to shrug at. The pages behind it are not.
Social graph. Who the store links to whom through shared meetings, group chats and a closeness score. Each circle opens to its members and to the evidence behind it.
What it concluded
Kinship scorecard. The family bindings inferred by the daemon.
Its card on the landing page is cut down to the people it names:
Family, as the scorecard has it
Six people, six relationships, and a subtitle saying nobody typed any of it. That holds for the scores; some of what they are computed from, you did type (a relation on a contact card, an emergency contact, Family Sharing). A mother, a father and a daughter at 0.960, which is as high as these columns go; a brother, a son and a sister at 0.500.
Below that is the part I find hardest to argue with. Nine separate checks (the partner column, the composite score, the household group entity, the Family Sharing token, the iCloud Family flag, top twelve-month contact, a Photos face cluster, a Contacts record, a reachable handle), and the card counts how many of them land on the same person. Eight of nine on the mother; seven on the father, and seven on Priya Sandoval, the partner, who is not in the list above: iKnow lists the relationships that roll up into another column (mother and father into parent), and partner rolls up into nothing. The join found the partner anyway.
The card is a summary of one table, and iKnow draws the whole table too:
Every person, every column
Sorted by familyAndFriends, the broadest of the scores. The seven at the top each light up their own relationship and the column it rolls up into (mother and father into parent, sister and brother into sibling, son and daughter into child), and the partner is also a colleague. Further down are the friends and the rest of the office. Under them, almost everyone else is the same two cells: one repeated value on family and another on familyAndFriends, which is what the classifier writes when it has nothing to say. Two columns (alumni and unknown) are never used at all.
The scores in these two shots are invented, and more generous than the real thing. On the Mac we took apart, only mother reached the top of the ladder; the few others it scored at all got one small vote on every family label at once, father and brother alike. What the fixture keeps is the table's grain: it only ever writes a handful of values (0.125, 0.25, 0.5 and 0.96), and most people sit on one default.
The face index. A face cluster for everyone in your photos.
Its co-occurrence graph does not use a single contact, message or calendar entry. It is built from your photographs alone:
The face co-occurrence graph
Two faces are linked when they appear in the same photograph, and that is the only input: 8,904 clustered faces over the 1,643 photographs that hold more than one. The labels are fragments of each cluster's local identifier, because there are no names to show. The owner is the hub. The knot on the left is the family, the group at the bottom right is work, and the two never share a frame.
Each node wears its cluster's key face, read out of the photo library and blurred by iKnow's own switch for sharing the screen. Under the blur there is nobody: the fixture has no photo library, so every face is a synthetic portrait painted for it.
This is the page's own honest point: the graph points at the face clusters and can name almost none of them (three of the twenty-nine, in the fixture). It does not need to. Who stands next to whom, how often, and which groups never meet is all there without a single name, and whoever knows the household can put the names back on in a second.
Guessed or given. What you typed in and what the Mac worked out for itself live in the same table. A confidence score is the only thing separating them.
What it recorded
A year of contact. Who you talked to, when, and not a word of message text (and it does not need any to tell when you are asleep).
Its card on the landing page is the one that gets the reaction, and it contains no inference at all.
A year of who you talked to
A year of contact, per person, split incoming and outgoing, with call counts and a last-seen date, across five messaging apps — and, exactly as the subtitle says, not one word of message text. None of this is content. It is all metadata, and it is enough.
The last line is the one to read twice: the hours it can read as sleep.
iKnow draws that line too, from the same log folded onto a single week:
Weekday against hour of day
Every cell counts the messages and calls that fell in one hour of one weekday, over the year. The working week is in there, and so are the evenings and the late weekend mornings; and so is the pale band from one to seven, every night. Nobody stored a sleep schedule. The quietest six-hour stretch falls out of the timestamps for free.
That is the general shape of this store: almost nothing in it had to be collected, because almost everything in it is a consequence of something that was.
The calendar. The one layer that knows where you will be: the hour, the room, the attendees and the dial-in.
What you withdrew. Withdrawing a fact does not remove it. The row moves to an expired table and keeps its confidence and provenance.
The machinery
The store. The file itself: what it models, and two real rows expanded into everything they touch.
Device fingerprint. Every app installed on the Mac is written down in plain text, next to a token that is an unsalted SHA-256 of that same app identifier, so the page recomputes it in your browser and you can watch it match.
Who else reads it. The graph is the first copy, not the only one. This page maps the views that subscribe to it, the databases they publish into, the tables that repeat the same facts, the streams coming in from hardware paired with the Mac, and the machinery that is set up but has not run yet.
A note on macOS 27. macOS 27 was released on September 14, 2026. After the upgrade to 27.0.1, the graph withdrew most of the rows it had built from Contacts, Calendar, Siri Suggestions, Family Sharing and the app catalog, and rebuilt them over the following day. Some pages of iKnow may not work fully on macOS 27 yet.