Command-line tool inspired by the DikuMUD CONSIDER command. Look up people in Microsoft Graph, enrich career history via People Data Labs, and resolve GitHub identities.
See PLAN.md for design details.
Answering a simple “who is this person?” often means opening the corporate directory and LinkedIn, running the same search twice, and mentally joining the person's role, reporting chain, location, and employment history. con does
that identity resolution and aggregation in one command.
Keeping the workflow in the terminal also avoids a less obvious productivity cost: opening LinkedIn for a two-minute lookup and losing the next fifteen minutes to the feed. con returns the relevant facts and leaves you in your
development context.
An AMD colleague can be resolved in the directory and enriched in one pass:
$ con -l +2 "mark papermaster"
Papermaster, Mark (EVP & Chief Technology Officer), located in Austin, TX, B100.T.304
Reporting chain:
-> Su, Lisa (Chair & Chief Executive Officer)
LinkedIn (PDL): mark papermaster · chief technology officer and executive vice president
amd · santa clara, california, united states · in role since 2019-01
Works at configured company: yes (current).
Shared employers: amd (2025-08–present)
Roles:
- board member @ penguin solutions (2022-09–present)
- chief technology officer and executive vice president @ amd (2019-01–present)
linkedin.com/in/mark-papermaster-66914925For someone outside the corporate directory, --at supplies evidence that
narrows the PDL lookup:
$ con -l --at microsoft +2 "mustafa suleyman"
No match for 'mustafa suleyman' in the Microsoft 365 directory; they do not appear to be a coworker.
LinkedIn (PDL): mustafa suleyman · executive vice president, frontier models and strategy
microsoft · redmond, washington, united states
Works at configured company: no match in history.
Roles:
- executive vice president, frontier models and strategy @ microsoft
- chief executive officer, microsoft ai @ microsoftThese examples are abbreviated. Directory details depend on the tenant, and PDL is an independently maintained dataset whose titles and dates can lag the live LinkedIn profile.
- Microsoft 365: a corporate account that can read your tenant directory.
Run
con auth microsoftonce to complete device-code authentication. This is required for normal name lookups. - LinkedIn-style career data: a People Data Labs API key for
-l, stored in[pdl] api_keyorPDL_API_KEY.condoes not ask for or use LinkedIn credentials.- Note: People Data Labs offers a free "Testing" tier which offers 100 credits/month.
- GitHub: public lookups work anonymously, but authentication avoids the
lower anonymous rate limit. Use
[github] token,CON_GITHUB_TOKEN/GITHUB_TOKEN, or an existinggh auth loginsession. - Runtime: Python 3.10+ and either
uvorpip.
con [-l] [+N] "firstname lastname"
con -g [-l] [+N] "github-handle"
con --json ...
con --md ...
con config
con auth microsoft
| Flag | Meaning |
|---|---|
| (default) | MS Graph people search + manager chain (depth 2) |
-l |
PDL enrichment (career / overlap) |
-g |
Treat query as GitHub login |
--at COMPANY |
Company qualifier for -l; required for non-coworkers |
+N |
How deep to go in every list returned (see below). Default +2. +0 = all the way |
--json / --md |
Machine or markdown output |
con is a research tool, not a per-source data manipulator. One number answers "how deep history do you want?" and applies to every list eventually returned:
- Directory: manager / reporting-chain length
- PDL (
-l): most recent employment roles (current and past treated the same)
Defaults to 2 when omitted. +0 means full depth (walk to CEO / all roles). A value at or above the length of the list simply returns the whole list.
| Code | Meaning |
|---|---|
0 |
The lookup ran, including when the person is simply not in the directory (not every name is a coworker) or a GitHub handle does not exist |
1 |
Every requested source failed to answer (not authenticated, network/API error) |
2 |
Usage problem or missing configuration |
PDL credit exhaustion never changes the exit code: -l degrades to a notice while directory and GitHub results still print. The same applies when a PDL capability is missing from your plan or no profile matches.
Examples:
con "Marco Nicosia"
con -l +3 "Mark Papermaster"
con -g menicosia
con -g -l menicosia
con -l --json "Mustafa Suleyman"See skill/SKILL.md — wrap con --json for Cursor/Claude.
cd /path/to/con
# Install with uv
uv venv
source .venv/bin/activate
uv pip install -e .
# Or install with pip
python3 -m pip install -e .
# or without install:
PYTHONPATH=src python3 -m con.cli --helpRequires Python 3.10+. No third-party runtime dependencies (stdlib only).
uv buildThis creates the standard artifacts in dist/:
con-<version>-py3-none-any.whlcon-<version>.tar.gz
Install the wheel directly with:
uv pip install dist/con-<version>-py3-none-any.whlcon configWrites ~/.con.ini. If both ~/.con.ini and ~/.con.json exist, INI wins and JSON is ignored (with a warning).
Minimal example:
[company]
name = Advanced Micro Devices, Inc.
linkedin_name = AMD
[user]
display_name = Marco Nicosia
email = marco.nicosia@amd.com
linkedin_url = https://www.linkedin.com/in/menicosia
[pdl]
api_key = YOUR_PDL_KEY
billing_cycle_start = 2024-01-15
[microsoft]
token_path = ~/.config/microsoft-graph/token.json
[github]
token =
[output]
default_format = humancon auth microsoftcon independently implements Microsoft Graph authentication and API calls using Python's standard library. It shares the same token-file and authentication pattern as AMD's m365 skills (~/.config/microsoft-graph/token.json), so you can re-use an existing token.
- Free tier allotments are per product (e.g. ~100 Person Enrich, ~100 Person Search, only ~5 Person Identify per month).
- Contact fields may be obfuscated on free plans;
condoes not need them. - When credits are exhausted,
-lprints LinkedIn enrichment not available (with replenishment date) and still returns directory / GitHub results. - Set
billing_cycle_startto your plan start date so replenishment uses the monthly anniversary; otherwise the date is estimated as the next calendar month start (UTC).
Developer note: Only an HTTP 402 means credits are actually spent. The x-totallimit-remaining
header is recorded for reference but never blocks a request: PDL reports it
per product, so an endpoint your plan excludes returns 0 while your Person
Enrich allotment is untouched. con never disables an endpoint on its own — it
asks the API every time, since a 402 costs nothing. Rate limiting (429) is
reported separately from exhaustion.
| Step | API | Cost |
|---|---|---|
| 1. Work email (directory hits only) | Person Enrich | 1 credit per match; a 404 no-match is free |
| 1b. Qualified lookup | Person Enrich | 1 credit per match; a 404 no-match is free |
| 2. Same-name fallback | Person Search | 1 credit per record returned; zero results are free |
| — | Person Identify | Not used. Free plans get only ~5 credits/month |
When the corporate directory supplies a work email, that is tried first: email is the strongest identifier PDL accepts and needs no name at all, so it still lands when the directory's spelling differs from the profile's (nicknames, married names, transliterations). It costs nothing extra — a miss is free, and a hit spends the same single credit the name lookup would have.
Person Enrich needs a qualifier alongside a name (company, location, country),
so a bare name cannot be enriched directly. When Enrich misses, con falls back
to Person Search with an exact-name query, capped by [pdl] search_candidates
(default 5, hard maximum 10). That cap is a spending limit: a five-result
picker costs up to five Search credits. Search records are complete, so the
profile you pick needs no follow-up Enrich call.
Naming your qualifier is cheaper and more accurate than falling back to Search:
con -l --at meta "alexandr wang" # 1 Enrich credit, no Search fallback neededWith -g -l, the GitHub profile's company and location are used as qualifiers
automatically. Names from the Microsoft directory arrive as "Last, First" and are
normalized to given-name-first before being sent to PDL.
con only qualifies a PDL lookup with a company that some evidence supports: an
explicit --at, a hit in the corporate directory, or the GitHub profile. Roughly
half of all lookups are not coworkers, so a directory miss is treated as
evidence the person works elsewhere — the configured employer is not silently
used as the qualifier. In that case Enrich is skipped (it requires a qualifier)
and the name goes straight to Search, unnarrowed. The directory and PDL are
independent: neither has to find the person for the other to answer.
A Person Search result matched on name alone is only a guess. When the chosen
record has no tie to a qualifying company — or when there was no qualifier to
begin with — output is labeled Low confidence (and match_confidence: "low"
in --json), because same-name strangers are common. Use --at to resolve
those. The caution never names a company that was not actually being tested.
Optional token in config, or CON_GITHUB_TOKEN / GITHUB_TOKEN, or gh auth token.
python3 -m pip install -e ".[dev]"
pytest- PDL is not live LinkedIn; data can lag.
- Graph People search ranks by relevance to you.
- GitHub org list is public memberships only.
- Do not use unofficial LinkedIn scrapers or broken “LinkedIn MCP” apps that call gated partner APIs.