Mastodon Politics, Power, and Science: People First
Showing posts with label People First. Show all posts
Showing posts with label People First. Show all posts

Thursday, November 12, 2026

People First, Not App First

 J. Rogers, SE Ohio

Every contact system you've ever used has the same flaw: it's app-first.

Contacts is a silo. Mail is a silo. Facebook is a silo. Ancestry is a silo. The person you actually know is scattered across all of them, and the only integration layer is you — manually copying context from one app to another, remembering that this email belongs to that Facebook handle, that this phone number belongs to the same person whose mother you found on a genealogy site three years ago.

The app is the primary object, and the person is a record inside it. That's backwards.

The person is the node

I'm building a contact model in DataObj where the person is the primary object, and everything else hangs off them. The entry point is a thumbnail — a small image of each person or company you know. That thumbnail isn't a picture of the person. It's the handle on the person. Click it and you get a full page: everything you know about them, the projects you're both in, their work, their family members you know, their email, phone, IM, social accounts. Drag it into a project. Drop a document on it to send. Wire it to another thumbnail to create a relationship.

All information comes through the thumbnail. One handle means one place information enters. No second address book to keep in sync.

Connectors are loadable objects

Email, phone, Facebook, Google Contacts, Apple Contacts, Ancestry — none of these are fields on a person record. They're connectors: loadable objects that give you methods. The connector is you — your credentials, your session, your transport, one instance shared by everyone on the page. Their identity on that platform is a property on them.

This means you configure Facebook once, not once per person. Sending is "my connector authenticates as me and addresses their handle." Receiving is a reverse lookup: the connector sees a message from a platform ID, the fabric resolves ID to person node, and it lands on that thumbnail. Their Facebook ID is effectively an alias — the address of their thumbnail on that network.

The page builds itself from what's loaded. If the Facebook connector isn't loaded, that section isn't there. Adding Slack support is a new .object file with declared dependencies and a version — it loads alongside everything else, and every person node gains a Slack method on next load. The Person class never changes.

Merging is linking, not collapsing

Import your Facebook friends and you get a list of identities. Import your Google Contacts and you get phone numbers and emails. Import your Ancestry tree and you get nodes plus the edges between them — mother-of, father-of, sibling-of — already a graph.

The merge problem is the same in every case: two thumbnails are the same person if they're aliases of one node. The system notices that two nodes share a name, a photo, a mutual connection, an email, or a phone number, and recommends a merge. Merging isn't copying one record into another and deleting the duplicate. It's pointing a second alias at the existing node. Their Facebook messages and their LinkedIn messages now land on the same thumbnail, because the alias table has two rows for that person.

And because it's a link and not a collapse, undoing it is just removing the link. The record that was aliased becomes its own node again, with everything it had. Nothing was destroyed, so nothing needs restoring. You can merge optimistically. If it's wrong, unlink — no "are you sure, this can't be undone" dialog, because it can.

The family tree fills in around the people you know

Ancestry is different from the social imports because it brings topology. Your mother is probably already a node you know. The import shouldn't create a second one — it should recognize her, alias the ancestry record to the existing node, and wire her parents in above her. Same for siblings you already have.

The tree fills in around the people you actually know, rather than duplicating them. Unlink the ancestry connector and those nodes stay, but lose their tree edges — or the whole branch drops without touching the people you knew independently.

Projects are aliases too

A project view holds thumbnails that are aliases of the person objects. Being in a project doesn't duplicate the person — it's a handle. Edit a phone number from the project view and it changes everywhere. Remove them from the project and the person still exists. "Send info to everyone on the project" is a fan-out through the aliases.  This can connect to github and see your projects and people you are connected to there as well. 

The relationship graph — son-of, mother-of, employee-of, subsidiary-of — is a topology view, the same way a spreadsheet view is a window onto a table. Nodes and typed edges. The same objects can be shown as a list, a roster, or a graph without changing the model.

Why this works now

All of this is possible because of primitives that already exist in the fabric: aliases, live projections, dataflow subscriptions, loadable versioned objects. The person isn't a special new thing. It's the same pattern as everything else, pointed at a different problem.

App-first architectures can't do people-first, because the silo is the data model. When Contacts owns the contact, the contact can't also be owned by Mail and Facebook and Ancestry without duplication and drift. When the person node is the model and the apps are just wires, the silo disappears.

The thumbnail is the entry point. The person is the node. Everything else is a connector.

People-First Connector Plan

The goal of this phase isn't a finished contact manager. It's to build enough connectors, spanning enough different shapes, that the common method set becomes visible. The connectors are probes: each one tells you something about what a "connector" actually is, and the comparison tells you where the abstraction boundary sits.


Phase 1 — The Four Starters

Each of these is chosen because it stresses a different axis. Build them in isolation, don't try to share code yet.

GitHub connector

Proves: org/people edges and hierarchical membership.

  • Auth: OAuth app or personal access token.

  • Fetch: authenticated user, their orgs, repos, collaborators, team members.

  • Import shape: people (authors, collaborators, org members) plus edges — member-of(org), contributes-to(repo), maintains(repo).

  • Send: minimal. Issues and comments could be a send path, but GitHub is mostly a directory for this purpose.

  • Unique feature: edges carry hierarchy — org contains team contains repo.

Mail connector

Proves: bidirectional messaging and frequency-weighted edges.

  • Auth: IMAP + SMTP, or Gmail OAuth (this is the real auth cost — budget for it).

  • Fetch: messages, threads, addresses from From/To/Cc.

  • Import shape: people from addresses, plus a corresponds-with edge that carries recency, frequency, and last-contact timestamp as edge properties.

  • Send: yes — this is your first true send path.

  • Receive: inbound mail routes to person node via email alias.

  • Unique feature: the same edge type carries temporal data. This is what makes the graph useful for "who should I follow up with."

Facebook connector

Proves: OAuth-heavy identity import and profile-pic-as-thumbnail.

  • Auth: OAuth with Facebook Login (heavily locked down post-2018; expect to request only public_profile and user_friends, and possibly need app review).

  • Fetch: friends list, profile pics, public profile fields.

  • Import shape: people + friend-of edge.

  • Send: Messenger API (requires app review and platform approval — plan for the friction).

  • Receive: webhook for incoming messages.

  • Unique feature: profile pic flows directly into the thumbnail slot. This is the first connector that populates the handle itself.

Ancestry connector

Proves: topology import — nodes and edges arriving together as a graph.

  • Auth: Ancestry has no public tree API as of writing. Realistic paths: (a) GEDCOM file import from an Ancestry export, (b) manual tree scraping via session, (c) partnership with a genealogy API aggregator. Flag this in the plan as an integration risk — the connector's shape is still worth building, but the fetch method may be GEDCOM-import for v1.

  • Fetch: people + family edges (parent-of, child-of, spouse-of, sibling-of).

  • Import shape: edge-primary. This is the first connector where the edges matter more than the records.

  • Send: none. Read-only directory.

  • Unique feature: edges are the payload, not a side effect. Tests whether the connector abstraction can carry topology.

Phase 1 milestone: four connectors, four different shapes (edges-with-hierarchy, bidirectional-messaging, identity-import, topology-import), each independently working. Now you can start comparing.


Phase 2 — The Next Few

Add one connector per remaining shape, not more than one per shape until Phase 3 tells you what's missing.

Google Contacts / Apple Contacts connector

Shape: flat directory with rich fields.

  • Auth: Google People API OAuth, or CardDAV for Apple.

  • Fetch: name, phone, email, address, birthday, photo.

  • Import shape: people only, no edges (except maybe knows for co-contacts if you want it later).

  • Send: none directly — this is a field-fill source, not a channel.

  • Proves: the connector whose only job is to enrich existing nodes, not create new ones.

Slack or Discord connector

Shape: org-scoped messaging with workspace membership.

  • Auth: OAuth (Slack) or bot token (Discord).

  • Fetch: workspace members, channels, message history.

  • Import shape: people + member-of(workspace) + participates-in(channel) edges.

  • Send: yes — DM or channel post.

  • Receive: webhook for incoming messages.

  • Proves: a second bidirectional connector with a different auth model. If Mail and Slack converge on the same method set, that's the shape of "messaging connector."

LinkedIn connector

Shape: professional graph with org structure.

  • Auth: OAuth (LinkedIn's API is also heavily restricted; expect to request r_liteprofile and r_emailaddress at minimum).

  • Fetch: connections, current and past positions, employers.

  • Import shape: people + works-at(company) + worked-at(company, dates) edges.

  • Send: minimal.

  • Proves: whether "works-at" is a first-class edge type or a generic related-to with a kind property. This is a design fork worth seeing empirically.

Calendar connector (Google Calendar or Outlook)

Shape: temporal people-linkage — events as the unit.

  • Auth: OAuth.

  • Fetch: events, attendees, recurring series.

  • Import shape: people from attendee lists + attended(event) edges with time properties + optionally co-attended edges between people.

  • Send: yes — calendar invites.

  • Proves: whether the connector abstraction handles a source whose primary object isn't a person. This is the one most likely to reveal an abstraction gap.

Phase 2 milestone: eight connectors, spanning four or five distinct shapes. Now the comparison is meaningful.


Phase 3 — The Comparison

This is the actual deliverable of the plan. Don't code it as a spreadsheet — code it as a report. For each connector, list:

  1. Published methods — what verbs does it expose? (configure, authenticate, fetch, resolve, send, receive, sync, status, and whatever else emerged.)

  2. Input shape — what does fetch return? people, edges, both, events, messages?

  3. Output shape — what can send address? a person via platform ID, a channel, an event?

  4. Auth model — OAuth, token, file import, session?

  5. Receive model — webhook, poll, IMAP IDLE, none?

  6. Edge types produced — free-form list.

  7. Unique methods — the ones that don't appear in any other connector.

Then answer:

  • What methods appear in all eight? That's the irreducible connector contract.

  • What methods cluster? Messaging connectors share a send/receive pair. Directory connectors share fetch-and-enrich. Topology connectors share edge-primary fetch. These clusters are the candidate sub-shapes.

  • What's unique to one? That's either a feature of that connector, or the sign that the "connector" abstraction needs a category it doesn't yet have.

  • Where does the variation live? Is it configuration (same method, different parameters), optional methods (every connector has fetch, only some have send), or category (topology connectors are a different class)?

The Phase 3 report should conclude with one sentence per connector describing its shape, and one paragraph proposing the shared contract. That paragraph is what Phase 4 acts on.


Phase 4 — Extract the Shape

The outcome is one of three possibilities, and Phase 3 tells you which:

Option A — a Connector template

If eight connectors share six or seven methods exactly, and the differences are all optional or configuration, then the template is: a connector is a .object that publishes a fixed method set, with flags for which optional methods it implements. This is the TableView pattern — one template, many instances, variation via properties.

Option B — a Connector protocol plus categories

If the eight divide cleanly into three or four shapes (directory, messaging, topology, temporal), then the abstraction is: every connector implements the common methods; each category adds a category-specific method set. This is the four-way dispatch pattern — exec_workflow is one shape, with template/proc/workflow/mcp as declared types. Connector dispatch would be directory/messaging/topology/temporal, with the common methods always present and the category methods declared per type.

Option C — no shared abstraction, just a convention

If the eight are genuinely divergent, the honest answer is that "connector" is a naming convention, not a type. Each connector is its own .object that happens to follow the same naming pattern. The person page assembles by discovering methods at runtime, not by consulting a class. This is the pattern the data_ext and Show discoveries already use.

My prediction, based on the shapes above: Option B. The connectors divide cleanly into directory, messaging, topology, and temporal, and the common methods are configure / authenticate / fetch / resolve / status. Send and receive are messaging-only. Edge-primary fetch is topology-only. Event-fetch is temporal-only. The comparison will confirm or reject this, and either result is a Phase 4 deliverable.


Phase 5 — What Comes After

Phase 4 tells you the contract. Phase 5 is where the contract gets used:

  1. The Person node model — now you know what fields and edge types connectors actually produce. The Person class is designed after this, not before. Fields for what every connector produces; edges for what at least two connectors produce; a generic property slot for what only one does.

  2. The merge/recommendation logic — the matching signals are visible in Phase 3 (email, phone, name, photo, mutual edges). The recommendation engine keys on whichever two or three signals appear most reliably across connectors.

  3. The Person page UI — it assembles from the loaded connectors. The rendering code doesn't know about Facebook or Mail; it discovers methods by name from the connector objects and renders a section per discovered verb. Adding a connector doesn't touch the page.

  4. The manifest for the MCP seam — the person model and its connectors publish to /Root/mcp the same way agents do. The same containment-is-publication rule.

  5. The next connector — because by now the contract is proven, adding a ninth is a same-day job, not a project.


Risks and Realities

  • Ancestry has no public tree API. GEDCOM import is the realistic v1. The connector's shape is still worth building to prove the topology case.

  • Facebook API is heavily restricted post-2018. Expect app review and limited scopes. The connector's shape is still worth building.

  • LinkedIn is similarly restricted. Expect r_liteprofile and r_emailaddress at most.

  • Mail via Gmail requires OAuth with Google's verification process — budget two to four weeks of lead time for the app review, not two to four days of coding.

  • None of these are architectural risks. They're integration frictions that every connector-based system faces. The architecture either handles them (it does — they're all fetch-and-map problems) or it doesn't, and Phase 1 will tell you.


The One-Sentence Summary

Build eight connectors across four shapes, compare their published methods, and let the comparison decide whether "connector" is a template, a protocol with categories, or a convention — because the answer determines whether the Person node is designed before or after the connectors, and that ordering is the whole plan.


Player Portal in Mega Mappers

Codex Engine: Player Portal, Auth, Rules-as-MCP & AI NPCs (Pure Node-Tree Edition) Defining game rulesets (D&D 5e, Pathfinder, Cyber...