# LinkedIn Extension — operator guide

Capture a LinkedIn profile or DM thread to your Maxy graph with one click. The plugin ships a small Chrome extension; the admin already knows how to receive its payloads.

## Install (one time)

1. Open `chrome://extensions`.
2. Toggle **Developer mode** on (top right).
3. Click **Load unpacked**.
4. Select `platform/plugins/linkedin-extension/extension/` on disk.
5. Click the puzzle icon → pin **Maxy LinkedIn Ingest** → open its options.
6. Paste two values:
   - **Admin host** — your tunnel URL, e.g. `https://your-tunnel.example.com`.
   - **Session key** — open your admin browser, copy the value of `session_key` from the cookie. (Same key the admin uses to authenticate every other admin request.)
7. Save. The pill is now armed.

## Use

- **Profile** — open any `https://www.linkedin.com/in/<slug>/` page. An **Add to Maxy** pill appears in the top section. Click it. Within a few seconds the pill turns green: the profile is in your graph.
- **DM thread** — open any `https://www.linkedin.com/messaging/thread/<id>/` conversation. The same pill appears. Click it; the full transcript is captured plus the participants and any explicit commitments (meetings booked, actions promised, prices discussed).
- **Re-click** — the pill is idempotent. Re-clicking the same URL refreshes the document body and regenerates the summary; identities and entities `MERGE` rather than duplicate.

## What lands in the graph

Every click produces **one `:KnowledgeDocument`** keyed on the page URL, holding the verbatim scraped text as its body and a child `:Section:Note` for the LLM summary. Structured entities layer on top, but only when the body **assertively states** them:

- A `:Person` for the profile subject (or each thread participant), `MERGE`d on canonical keys.
- A `:Organization` for an asserted current employer, with a `WORKS_AT` edge from the person.
- An `:Event` with `ATTENDED_BY` edges when a meeting time is explicitly proposed and confirmed.
- A `:Task` with `RAISED_BY` / `ABOUT` edges when an action is promised without a specific time.
- A `:Service` / `:PriceSpecification` when an offer is discussed.

Soft signals ("interested in chatting", "would love to compare notes") stay in the document body. They are never promoted to graph nodes.

The plugin will never create `:Communication`, `:ConversationArchive` rows (i.e. KnowledgeDocument nodes that carry `conversationIdentity`), or `:Message` nodes — those shapes are reserved for other flows (live chat, archive ingest).

## When the pill turns amber

The pill shows **Sign in to Maxy** when your session key has expired. Click it to open the options page; paste a fresh `session_key` from your admin browser; save. The next click on the LinkedIn pill will succeed.

## When the pill turns red

- **Missing: ...** — LinkedIn shipped a DOM change and the extractor cannot find a required field. Open a console tab on the LinkedIn page and check the `[linkedin-ext-scrape]` log line for the field names. Drop a ticket pointing at the affected selector; the [`SKILL.md`](../../plugins/linkedin-extension/skills/linkedin-extension/SKILL.md) lists the selector table and the steps for adding a fallback.
- **Capture failed** — the admin reached, but the request did not complete cleanly. Check the admin logs (`journalctl -u maxy.service | grep linkedin-ingest`). The `[linkedin-ingest-route]` lines name the reason (`schema`, `dispatch-failed`).

## Related plugins

- **linkedin-import** — bulk ingest of the LinkedIn ZIP export (history). Different surface; both ship and complement each other.
- **memory.document-ingest** — the generic ingest pipeline this plugin's payloads route through. Future communication surfaces (email, Telegram, WhatsApp) plug in here too.
