whoelse 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. whoelse-0.1.0/.github/PUBLISH.md +23 -0
  2. whoelse-0.1.0/.github/workflows/release.yml +38 -0
  3. whoelse-0.1.0/.github/workflows/test.yml +15 -0
  4. whoelse-0.1.0/.gitignore +6 -0
  5. whoelse-0.1.0/.well-known/whoelse.json +21 -0
  6. whoelse-0.1.0/CHANGELOG.md +20 -0
  7. whoelse-0.1.0/DECISIONS.md +151 -0
  8. whoelse-0.1.0/LICENSE +21 -0
  9. whoelse-0.1.0/PKG-INFO +313 -0
  10. whoelse-0.1.0/README.md +292 -0
  11. whoelse-0.1.0/docs/LAUNCH.md +66 -0
  12. whoelse-0.1.0/docs/clusters/README.md +10 -0
  13. whoelse-0.1.0/docs/clusters/arxiv-mcp-servers.md +54 -0
  14. whoelse-0.1.0/docs/clusters/claude-code-session-sync.md +54 -0
  15. whoelse-0.1.0/docs/clusters/dicom-rust.md +31 -0
  16. whoelse-0.1.0/docs/clusters/llm-token-cost-dashboards.md +22 -0
  17. whoelse-0.1.0/docs/clusters/obsidian-static-site-generators.md +31 -0
  18. whoelse-0.1.0/docs/clusters/pii-anonymization-for-llms.md +21 -0
  19. whoelse-0.1.0/docs/demo.png +0 -0
  20. whoelse-0.1.0/plugin/.claude-plugin/plugin.json +11 -0
  21. whoelse-0.1.0/plugin/README.md +18 -0
  22. whoelse-0.1.0/plugin/skills/dont-build-it-alone/SKILL.md +26 -0
  23. whoelse-0.1.0/pyproject.toml +40 -0
  24. whoelse-0.1.0/registry/.github/workflows/check.yml +65 -0
  25. whoelse-0.1.0/registry/README.md +14 -0
  26. whoelse-0.1.0/server.json +26 -0
  27. whoelse-0.1.0/src/whoelse/__init__.py +3 -0
  28. whoelse-0.1.0/src/whoelse/brief.py +168 -0
  29. whoelse-0.1.0/src/whoelse/config.py +65 -0
  30. whoelse-0.1.0/src/whoelse/duplicates.py +770 -0
  31. whoelse-0.1.0/src/whoelse/http.py +159 -0
  32. whoelse-0.1.0/src/whoelse/match.py +638 -0
  33. whoelse-0.1.0/src/whoelse/models.py +100 -0
  34. whoelse-0.1.0/src/whoelse/network.py +511 -0
  35. whoelse-0.1.0/src/whoelse/peers.py +123 -0
  36. whoelse-0.1.0/src/whoelse/profile.py +348 -0
  37. whoelse-0.1.0/src/whoelse/scripts/__init__.py +0 -0
  38. whoelse-0.1.0/src/whoelse/scripts/first_run.py +67 -0
  39. whoelse-0.1.0/src/whoelse/server.py +499 -0
  40. whoelse-0.1.0/src/whoelse/sources/__init__.py +2 -0
  41. whoelse-0.1.0/src/whoelse/sources/arxiv.py +103 -0
  42. whoelse-0.1.0/src/whoelse/sources/card.py +80 -0
  43. whoelse-0.1.0/src/whoelse/sources/github.py +135 -0
  44. whoelse-0.1.0/src/whoelse/sources/huggingface.py +96 -0
  45. whoelse-0.1.0/src/whoelse/sources/openalex.py +181 -0
  46. whoelse-0.1.0/src/whoelse/sources/orcid.py +95 -0
  47. whoelse-0.1.0/src/whoelse/watch.py +308 -0
  48. whoelse-0.1.0/src/whoelse/workspace.py +352 -0
  49. whoelse-0.1.0/tests/conftest.py +24 -0
  50. whoelse-0.1.0/tests/fixtures/arxiv_all-anonymization.json +3 -0
  51. whoelse-0.1.0/tests/fixtures/arxiv_all-citizen_appeals.json +3 -0
  52. whoelse-0.1.0/tests/fixtures/arxiv_all-nl2sql.json +3 -0
  53. whoelse-0.1.0/tests/fixtures/arxiv_all-open-weight_models.json +3 -0
  54. whoelse-0.1.0/tests/fixtures/arxiv_all-pii.json +3 -0
  55. whoelse-0.1.0/tests/fixtures/arxiv_all-public_administration.json +3 -0
  56. whoelse-0.1.0/tests/fixtures/arxiv_all-qwen.json +3 -0
  57. whoelse-0.1.0/tests/fixtures/arxiv_all-schema_linking.json +3 -0
  58. whoelse-0.1.0/tests/fixtures/arxiv_all-text-to-sql.json +3 -0
  59. whoelse-0.1.0/tests/fixtures/arxiv_all-text_classification.json +3 -0
  60. whoelse-0.1.0/tests/fixtures/arxiv_au_ana_ferreira.json +3 -0
  61. whoelse-0.1.0/tests/fixtures/arxiv_au_li_wei.json +3 -0
  62. whoelse-0.1.0/tests/fixtures/arxiv_au_vladimir_beskorovainyi.json +3 -0
  63. whoelse-0.1.0/tests/fixtures/arxiv_au_yusuf_demir.json +3 -0
  64. whoelse-0.1.0/tests/fixtures/arxiv_au_yuyu_luo.json +3 -0
  65. whoelse-0.1.0/tests/fixtures/card_amine.io.json +17 -0
  66. whoelse-0.1.0/tests/fixtures/card_sqlbot.dev.json +1 -0
  67. whoelse-0.1.0/tests/fixtures/github_me.json +3 -0
  68. whoelse-0.1.0/tests/fixtures/github_repos_anaferreira.json +18 -0
  69. whoelse-0.1.0/tests/fixtures/github_repos_apena-gamedev.json +19 -0
  70. whoelse-0.1.0/tests/fixtures/github_repos_besk-tech.json +38 -0
  71. whoelse-0.1.0/tests/fixtures/github_repos_notluo.json +1 -0
  72. whoelse-0.1.0/tests/fixtures/github_repos_ppapotti.json +18 -0
  73. whoelse-0.1.0/tests/fixtures/github_repos_ydemir.json +1 -0
  74. whoelse-0.1.0/tests/fixtures/github_search_anonymization.json +3 -0
  75. whoelse-0.1.0/tests/fixtures/github_search_citizen_appeals.json +3 -0
  76. whoelse-0.1.0/tests/fixtures/github_search_claude_code_backup.json +53 -0
  77. whoelse-0.1.0/tests/fixtures/github_search_claude_code_plugin_backup_conversations.json +53 -0
  78. whoelse-0.1.0/tests/fixtures/github_search_claude_code_plugin_backup_sessions.json +53 -0
  79. whoelse-0.1.0/tests/fixtures/github_search_claude_code_plugin_snapshot_sessions.json +53 -0
  80. whoelse-0.1.0/tests/fixtures/github_search_claude_code_sessions.json +53 -0
  81. whoelse-0.1.0/tests/fixtures/github_search_claude_code_sync_sessions.json +158 -0
  82. whoelse-0.1.0/tests/fixtures/github_search_claude_code_wearable.json +158 -0
  83. whoelse-0.1.0/tests/fixtures/github_search_nl2sql.json +3 -0
  84. whoelse-0.1.0/tests/fixtures/github_search_pii.json +3 -0
  85. whoelse-0.1.0/tests/fixtures/github_search_public_administration.json +3 -0
  86. whoelse-0.1.0/tests/fixtures/github_search_qwen.json +3 -0
  87. whoelse-0.1.0/tests/fixtures/github_search_schema_linking.json +3 -0
  88. whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_conversations_machines.json +158 -0
  89. whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_conversations_wearable.json +158 -0
  90. whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_sessions_devices.json +158 -0
  91. whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_sessions_machines.json +158 -0
  92. whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_sessions_wearable.json +158 -0
  93. whoelse-0.1.0/tests/fixtures/github_search_synchronize_claude_code_sessions_machines.json +158 -0
  94. whoelse-0.1.0/tests/fixtures/github_search_synchronize_claude_code_sessions_wearable.json +158 -0
  95. whoelse-0.1.0/tests/fixtures/github_search_text-to-sql.json +36 -0
  96. whoelse-0.1.0/tests/fixtures/github_search_text_classification.json +3 -0
  97. whoelse-0.1.0/tests/fixtures/github_search_todo_language_rust.json +53 -0
  98. whoelse-0.1.0/tests/fixtures/github_search_todo_rust.json +53 -0
  99. whoelse-0.1.0/tests/fixtures/github_user_anaferreira.json +10 -0
  100. whoelse-0.1.0/tests/fixtures/github_user_besk-tech.json +9 -0
  101. whoelse-0.1.0/tests/fixtures/github_user_kmori.json +10 -0
  102. whoelse-0.1.0/tests/fixtures/github_user_notluo.json +10 -0
  103. whoelse-0.1.0/tests/fixtures/github_user_ppapotti.json +9 -0
  104. whoelse-0.1.0/tests/fixtures/github_user_sqlbot.json +9 -0
  105. whoelse-0.1.0/tests/fixtures/github_user_ydemir.json +10 -0
  106. whoelse-0.1.0/tests/fixtures/github_users_alejandro_pe/303/261a.json +8 -0
  107. whoelse-0.1.0/tests/fixtures/github_users_amine_mhedhbi.json +4 -0
  108. whoelse-0.1.0/tests/fixtures/github_users_david_graus.json +14 -0
  109. whoelse-0.1.0/tests/fixtures/github_users_li_wei.json +14 -0
  110. whoelse-0.1.0/tests/fixtures/github_users_nikhil_rao.json +14 -0
  111. whoelse-0.1.0/tests/fixtures/github_users_paolo_papotti.json +8 -0
  112. whoelse-0.1.0/tests/fixtures/hf_dataset_search_anonymization.json +1 -0
  113. whoelse-0.1.0/tests/fixtures/hf_dataset_search_citizen_appeals.json +1 -0
  114. whoelse-0.1.0/tests/fixtures/hf_dataset_search_nl2sql.json +1 -0
  115. whoelse-0.1.0/tests/fixtures/hf_dataset_search_pii.json +1 -0
  116. whoelse-0.1.0/tests/fixtures/hf_dataset_search_public_administration.json +1 -0
  117. whoelse-0.1.0/tests/fixtures/hf_dataset_search_qwen.json +1 -0
  118. whoelse-0.1.0/tests/fixtures/hf_dataset_search_schema_linking.json +1 -0
  119. whoelse-0.1.0/tests/fixtures/hf_dataset_search_text-to-sql.json +13 -0
  120. whoelse-0.1.0/tests/fixtures/hf_dataset_search_text_classification.json +1 -0
  121. whoelse-0.1.0/tests/fixtures/hf_model_search_anonymization.json +1 -0
  122. whoelse-0.1.0/tests/fixtures/hf_model_search_citizen_appeals.json +1 -0
  123. whoelse-0.1.0/tests/fixtures/hf_model_search_nl2sql.json +1 -0
  124. whoelse-0.1.0/tests/fixtures/hf_model_search_pii.json +1 -0
  125. whoelse-0.1.0/tests/fixtures/hf_model_search_public_administration.json +1 -0
  126. whoelse-0.1.0/tests/fixtures/hf_model_search_qwen.json +1 -0
  127. whoelse-0.1.0/tests/fixtures/hf_model_search_schema_linking.json +1 -0
  128. whoelse-0.1.0/tests/fixtures/hf_model_search_text-to-sql.json +14 -0
  129. whoelse-0.1.0/tests/fixtures/hf_model_search_text_classification.json +1 -0
  130. whoelse-0.1.0/tests/fixtures/hf_user_amine-io.json +5 -0
  131. whoelse-0.1.0/tests/fixtures/hf_user_defog.json +5 -0
  132. whoelse-0.1.0/tests/fixtures/hf_user_sqlbot.json +1 -0
  133. whoelse-0.1.0/tests/fixtures/network_ana-ferreira.json +35 -0
  134. whoelse-0.1.0/tests/fixtures/network_evil.json +16 -0
  135. whoelse-0.1.0/tests/fixtures/network_expired.json +16 -0
  136. whoelse-0.1.0/tests/fixtures/network_kenji-mori.json +32 -0
  137. whoelse-0.1.0/tests/fixtures/network_repo_beskvladimir-create_whoelse-network.json +3 -0
  138. whoelse-0.1.0/tests/fixtures/network_tree_beskvladimir-create_whoelse-network.json +31 -0
  139. whoelse-0.1.0/tests/fixtures/network_yusuf-demir.json +33 -0
  140. whoelse-0.1.0/tests/fixtures/network_yuyu-luo.json +32 -0
  141. whoelse-0.1.0/tests/fixtures/openalex_author_orcid_0000-0000-0000-9999.json +1 -0
  142. whoelse-0.1.0/tests/fixtures/openalex_author_orcid_0000-0001-0000-0001.json +12 -0
  143. whoelse-0.1.0/tests/fixtures/openalex_author_orcid_0000-0001-9530-3327.json +1 -0
  144. whoelse-0.1.0/tests/fixtures/openalex_author_orcid_0000-0002-2222-3333.json +12 -0
  145. whoelse-0.1.0/tests/fixtures/openalex_authors_li_wei.json +48 -0
  146. whoelse-0.1.0/tests/fixtures/openalex_authors_vladimir_beskorovainyi.json +23 -0
  147. whoelse-0.1.0/tests/fixtures/openalex_authors_yusuf_demir.json +3 -0
  148. whoelse-0.1.0/tests/fixtures/openalex_authors_yuyu_luo.json +3 -0
  149. whoelse-0.1.0/tests/fixtures/openalex_works_author_A5000000001.json +341 -0
  150. whoelse-0.1.0/tests/fixtures/openalex_works_author_A5000000050.json +121 -0
  151. whoelse-0.1.0/tests/fixtures/openalex_works_author_A5000000102.json +3 -0
  152. whoelse-0.1.0/tests/fixtures/openalex_works_kw_citizen-appeals_p1.json +3 -0
  153. whoelse-0.1.0/tests/fixtures/openalex_works_kw_deep-learning_p1.json +3 -0
  154. whoelse-0.1.0/tests/fixtures/openalex_works_kw_enterprise-bi_p1.json +3 -0
  155. whoelse-0.1.0/tests/fixtures/openalex_works_kw_open-weight-models_p1.json +3 -0
  156. whoelse-0.1.0/tests/fixtures/openalex_works_kw_public-administration_p1.json +3 -0
  157. whoelse-0.1.0/tests/fixtures/openalex_works_kw_schema-linking_p1.json +3 -0
  158. whoelse-0.1.0/tests/fixtures/openalex_works_kw_text-classification_p1.json +3 -0
  159. whoelse-0.1.0/tests/fixtures/openalex_works_kw_text-to-sql_p1.json +321 -0
  160. whoelse-0.1.0/tests/fixtures/openalex_works_search_anonymization.json +3 -0
  161. whoelse-0.1.0/tests/fixtures/openalex_works_search_citizen_appeals.json +3 -0
  162. whoelse-0.1.0/tests/fixtures/openalex_works_search_nl2sql.json +3 -0
  163. whoelse-0.1.0/tests/fixtures/openalex_works_search_pii.json +3 -0
  164. whoelse-0.1.0/tests/fixtures/openalex_works_search_public_administration.json +3 -0
  165. whoelse-0.1.0/tests/fixtures/openalex_works_search_qwen.json +3 -0
  166. whoelse-0.1.0/tests/fixtures/openalex_works_search_schema_linking.json +3 -0
  167. whoelse-0.1.0/tests/fixtures/openalex_works_search_text-to-sql.json +3 -0
  168. whoelse-0.1.0/tests/fixtures/openalex_works_search_text_classification.json +3 -0
  169. whoelse-0.1.0/tests/fixtures/openalex_works_topic_T10181_p1.json +281 -0
  170. whoelse-0.1.0/tests/fixtures/openalex_works_topic_T10992_p1.json +3 -0
  171. whoelse-0.1.0/tests/fixtures/openalex_works_topic_T11714_p1.json +3 -0
  172. whoelse-0.1.0/tests/fixtures/openalex_works_topic_T12345_p1.json +197 -0
  173. whoelse-0.1.0/tests/fixtures/orcid_person_0000-0001-0000-0001.json +8 -0
  174. whoelse-0.1.0/tests/fixtures/orcid_person_0000-0001-1111-2222.json +13 -0
  175. whoelse-0.1.0/tests/fixtures/orcid_person_0000-0002-0000-0001.json +24 -0
  176. whoelse-0.1.0/tests/fixtures/orcid_person_0000-0002-2222-3333.json +8 -0
  177. whoelse-0.1.0/tests/fixtures/orcid_person_0000-0002-9035-7045.json +19 -0
  178. whoelse-0.1.0/tests/fixtures/orcid_person_0000-0003-0651-4128.json +19 -0
  179. whoelse-0.1.0/tests/fixtures/orcid_person_0009-0000-9342-5144.json +19 -0
  180. whoelse-0.1.0/tests/make_fixtures.py +375 -0
  181. whoelse-0.1.0/tests/test_duplicates.py +249 -0
  182. whoelse-0.1.0/tests/test_network.py +320 -0
  183. whoelse-0.1.0/tests/test_regressions.py +379 -0
  184. whoelse-0.1.0/tests/test_whoelse.py +161 -0
@@ -0,0 +1,23 @@
1
+ # Publishing checklist (author only)
2
+
3
+ ```bash
4
+ # 1. repository
5
+ gh repo create beskvladimir-create/whoelse --public --source=. --push \
6
+ --description "Who else is working on what you're working on? An MCP server that finds them, says what you could build together, and drafts the first message. Papers, code, datasets, models. Local. Free."
7
+ gh repo edit beskvladimir-create/whoelse --add-topic mcp --add-topic mcp-server --add-topic research --add-topic collaboration \
8
+ --add-topic openalex --add-topic arxiv --add-topic huggingface --add-topic claude --add-topic cursor --add-topic codex --add-topic ai-agents
9
+
10
+ # 2. the author's own card (so the first user of connected mode is the author)
11
+ # put .well-known/whoelse.json at https://vladimir.besk.tech/.well-known/whoelse.json
12
+
13
+ # 3. first live run, then paste 3 real lines of output into README under "What you get"
14
+ WHOELSE_MAILTO=vladimir@besk.tech python -m whoelse.scripts.first_run "Vladimir Beskorovainyi" --orcid 0009-0004-7005-6242
15
+
16
+ # 4. PyPI (optional, after the run)
17
+ python -m build && twine upload dist/*
18
+
19
+ # 5. registries: submit to modelcontextprotocol/servers (community list), Smithery, mcp.so, PulseMCP, Glama
20
+ ```
21
+
22
+ Launch post (one paragraph, no hype): what the pain is, what the tool did on the author's own name
23
+ (N people, M reachable, first replies), the install line, the card.
@@ -0,0 +1,38 @@
1
+ name: release
2
+ # One tag publishes everywhere: PyPI (trusted publishing, no token) and the official MCP Registry (GitHub OIDC).
3
+ # One-time setup on pypi.org: Your projects -> Publishing -> add a pending publisher for project "whoelse",
4
+ # owner beskvladimir-create, repository whoelse, workflow release.yml, environment pypi.
5
+ on:
6
+ push:
7
+ tags: ["v*"]
8
+ jobs:
9
+ pypi:
10
+ runs-on: ubuntu-latest
11
+ environment: pypi
12
+ permissions:
13
+ id-token: write
14
+ contents: read
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.12"
20
+ - run: pip install build && python -m build
21
+ - uses: pypa/gh-action-pypi-publish@release/v1
22
+ registry:
23
+ needs: pypi
24
+ runs-on: ubuntu-latest
25
+ permissions:
26
+ id-token: write
27
+ contents: read
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ - name: Install mcp-publisher
31
+ run: |
32
+ curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
33
+ - name: Version from the tag
34
+ run: |
35
+ V=${GITHUB_REF#refs/tags/v}
36
+ jq --arg v "$V" '.version = $v | .packages[0].version = $v' server.json > s.tmp && mv s.tmp server.json
37
+ - run: ./mcp-publisher login github-oidc
38
+ - run: ./mcp-publisher publish
@@ -0,0 +1,15 @@
1
+ name: tests
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ runs-on: ubuntu-latest
6
+ strategy:
7
+ matrix:
8
+ python: ["3.10", "3.12", "3.13"]
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - uses: actions/setup-python@v5
12
+ with:
13
+ python-version: ${{ matrix.python }}
14
+ - run: pip install -e ".[dev]"
15
+ - run: pytest -q
@@ -0,0 +1,6 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .pytest_cache/
4
+ dist/
5
+ *.egg-info/
6
+ .venv/
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "Vladimir Beskorovainyi",
3
+ "working_on": [
4
+ "text-to-SQL on open-weight models",
5
+ "classification of citizen appeals at national scale",
6
+ "machine transcription of historical archives"
7
+ ],
8
+ "open_to": [
9
+ "co-author",
10
+ "joint benchmark",
11
+ "cross-replication",
12
+ "talk together"
13
+ ],
14
+ "contact": "vladimir@besk.tech",
15
+ "languages": [
16
+ "en",
17
+ "ru"
18
+ ],
19
+ "updated": "2026-11-07",
20
+ "spec": "https://github.com/beskvladimir-create/whoelse#the-card"
21
+ }
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-11-07
4
+
5
+ First release.
6
+
7
+ - Profile from OpenAlex, arXiv, GitHub, Hugging Face, ORCID; namesakes are shown, never guessed.
8
+ - Discovery across papers (OpenAlex keywords and topics, arXiv preprints), code (GitHub) and models/datasets (Hugging Face); quantisation repacks filtered.
9
+ - Ranking with IDF-damped keywords so field-wide terms cannot carry a match.
10
+ - Identity guards: self-exclusion by ids, name merges need a second signal, organisations dropped.
11
+ - Reach: ORCID public contacts, GitHub profile, GitHub user search by full name (unique hit confirmed by repo subject), whoelse card at /.well-known/whoelse.json.
12
+ - joint_work_brief ranks formats by what each side actually has; draft_outreach gives facts and structure, never sends.
13
+ - Peers: add_peer, whats_new_from_peers, with concrete ways to support; no automated stars or follows.
14
+ - find_duplicates / propose_merge: what already exists for an idea, who won, what nobody has; a merge plan with one issue per author.
15
+ Relevance on job words only; synonyms; search totals and "at least" when capped; four honest verdicts (field / won / cluster / parts exist).
16
+ Merge limits per GitHub's acceptable use: 3-15 repositories, 10 issues a day, ledger, no forks/organisations/winners/own repos,
17
+ approval bound to the exact texts shown (plan_id), rate limit stops the run.
18
+ - plugin/: Claude Code plugin with a dont-build-it-alone skill; the same text serves as rules for Cursor, Codex and other MCP clients.
19
+ - publish_request / start_joint_work / whoelse-watch: an open registry of requests, a workspace with a third of the work done, a watcher that starts joint work on a mutual match.
20
+ - 70 offline tests on recorded fixtures; one-command first run.
@@ -0,0 +1,151 @@
1
+ # Decisions log
2
+
3
+ Kept so the reasoning survives the chat that produced it.
4
+
5
+ ## 2026-11-07, v0.1.0
6
+
7
+ **Why this exists.** Research into "Код популярности" showed the honest engine of recognition is third-party mentions born from joint work, not self-publishing. Joint work needs the right people. Nobody with overlapping work knows each other. That is the pain; whoelse is the lookup.
8
+
9
+ **What exists already (checked 2026-11-07).**
10
+ Sites: ResearcherCollab (~1.6k people, collab calls, AI matching in PRO), ResearchConnectX, ResearcherNet (Kolkata, ~650 people, institution sales), Collaboratium, Researchmate, CheckMyManuscript collaborator finder. All stop at "here is a person"; none proposes the joint work, none measures reach, none leaves academia.
11
+ MCPs: paper search (paper-search-mcp, arxiv-mcp-server, OpenArx), author profiles (OpenAlex MCP, ORCID MCP), AuthorProfileMCP (co-authors you already have, 1 star), sales people-search (Sixtyfour, Apollo). None does "with whom should I work next, and on what".
12
+
13
+ **Name.** `whoelse`: a question everyone asks. GitHub checked: `coauthor` taken (280 stars, other project, and too narrow); `kindred` noisy; `whoelse` only a 2-star unrelated repo.
14
+
15
+ **Shape.** MCP server, not a site: spreads through GitHub and MCP registries, works inside an agent that already knows the user, no cold-start registry, data stays local. First user is the author.
16
+
17
+ **Sources and rules.**
18
+ - OpenAlex: CC0 metadata; keyword ids (`keywords.id`) are far sharper than topics (a text-to-SQL paper lands in topic "Topic Modeling"). API key optional but recommended (shared per-IP budget without it).
19
+ - arXiv: CC0 descriptive metadata. Submitter emails are behind login, monitored, and forbidden for unsolicited contact. Never used. `arxiv:comment` carries the author's own GitHub/HF links, used to join papers to code.
20
+ - ORCID: public API, keyless. Only `visibility: public` emails. Needs `Accept: application/vnd.orcid+json`; XML fallback parser included.
21
+ - GitHub: REST, token optional. Acceptable Use names "automated starring or following" as rank abuse: whoelse never stars/follows.
22
+ - Hugging Face: keyless. Quantisations/repacks (`base_model:quantized:`, gguf/awq/gptq...) are not the author's work and are filtered.
23
+ - Platform rules checked earlier: X (OAuth is not consent for automated actions), LinkedIn (bots/inauthentic engagement banned), Meta (high-frequency account creation banned). Hence: one message, one person, sent by the user.
24
+
25
+ **Namesakes.** OpenAlex returned three "Vladimir Beskorovainyi" (Kharkiv, Volgograd, MIPT). Guessing by works_count picks the wrong person. whoelse refuses to guess and asks for ORCID/affiliation.
26
+
27
+ **Connected mode.** `/.well-known/whoelse.json` on the person's own site. No registry: the web is the directory. Card bonus in ranking (+0.2).
28
+
29
+ **Not built yet.** Joint proposal to both sides when both have cards (needs an inbox convention); per-source rate budgeting UI; Semantic Scholar as a second paper source; a `reach` index (what search/LLMs answer for the user's name) — belongs to the larger product, not this tool.
30
+
31
+ **Author.** Vladimir Beskorovainyi, sole author of all commits.
32
+
33
+ ## 2026-11-07, review round
34
+
35
+ Independent review found 25 items; 20 fixed, 2 rejected as non-bugs, 3 deferred. Live measurements on the author's own topics drove three design changes:
36
+
37
+ - **Reach is the bottleneck, not discovery.** Of 60 ORCID records behind the top text-to-SQL papers, 4 had a public email and 6 any URL. Of 60 fresh arXiv papers, 7 linked GitHub. So: a third channel, GitHub user search by full name, accepted only on a unique hit confirmed by repository subject (3 of 9 real names resolved; common names return 18–142 namesakes and are skipped).
38
+ - **Generic terms must not carry a match.** "large language models" was shared by nearly everyone in the pool. Keywords are now IDF-weighted over the candidate pool, with a hard-coded generic set damped to 8%.
39
+ - **Identity is guarded, not guessed.** Self-exclusion by ids, not name only; merge of records requires a second signal; organisations are detected on GitHub (type) and Hugging Face (overview) and dropped; an ORCID the user supplies is never stamped onto a namesake; CJK and accented names survive slug/norm.
40
+
41
+ Robustness: any non-JSON 200 (SPA fallback pages at /.well-known/whoelse.json) is a SourceError; one candidate's broken site cannot take the result down; Retry-After dates parse; arXiv rate-limit text does not crash; per-host concurrency caps; tool errors reach the model as text (ToolError).
42
+
43
+ Deferred: proposal to both card holders at once; PyPI release; Semantic Scholar as a second index.
44
+
45
+ ## 2026-11-07, verification round
46
+
47
+ Second independent pass (verifying the fixes) found one serious regression I had introduced: arXiv coauthors were keyed by the paper's GitHub link and collapsed into one person. Fixed: the link stays on the paper; a person merges only on a second signal. Also fixed: outreach now cites the overlapping work, not the newest; affiliation match is token-based (no "MIT" ⊂ "Smith College"); same paper is a merge signal; a full name the person typed into their own GitHub/HF profile is a merge signal except for common family names; Hugging Face profile is a reach channel; card `open_to` lifts matching formats (full paper still after a smaller step); user's namesakes are not dropped as "me"; by-name GitHub lookups capped at 8 without a token; 403+Retry-After retried; semaphores per event loop; headline grammar; namesake flag in lines. 40 tests.
48
+
49
+ ## 2026-11-08, connecting strangers
50
+
51
+ Vladimir's correction: finding people is not the product; two strangers ending up in one piece of work, fast, is. Knowing each other is a side effect. So: `start_joint_work` (a repository with a third of the work done, both names on it), `publish_request` (an open registry of what people want to build; one JSON per person in a public GitHub repo; no server), `whoelse-watch` (reads the registry, matches, creates the repository, invites, emails both; the user only has to not remove the tool). The honest waiting text keeps people in the queue: "37 are waiting, none on your topic yet; when one joins the work starts by itself and a link goes to you".
52
+
53
+ Two review rounds on this layer found and fixed: registry files are hostile input (strict schema; control and invisible characters stripped; names with markup rejected); impersonation by file (verification against the GitHub profile; CI requires ids.github == PR author AND that an existing file belongs to the author; workflow runs from base via pull_request_target); what verification cannot prove (that the account is the named researcher), answered by creating the repository private and publishing only after "in"; two watchers creating two repositories (one creator per pair by sorted name; repo name from the pair and the matched keyword, with a hash, never from either side's topic text); overwriting a collaborator's pushes (never write into an existing repo; check .whoelse.json sides); registry read from a 72-hour cache (tree uncached; files by blob sha through the git/blobs API, since raw.githubusercontent does not serve blob shas); SMTP sender forgery (no From → inbox only); state corruption and dry runs starting clocks. 65 tests, the registry CI script is executed in the test suite.
54
+
55
+ Known limit, stated in README: display-name verification is weak by itself; privacy-until-"in" is the real guard.
56
+
57
+ ## 2026-11-08, before you build it
58
+
59
+ Vladimir's observation: open source has twenty repositories for every idea, each with ten stars,
60
+ each author alone and wanting the same thing: a response. And agents happily build the 21st.
61
+ So: `find_duplicates` (GitHub search on the idea; keep what is actually the same thing by token
62
+ similarity; order by stars; feature matrix from a fixed vocabulary of feature words, so repository
63
+ descriptions can label but never speak; verdict first) and `propose_merge` (base = the living
64
+ leader, pushed within 90 days with the most stars, so its stars and users carry over; what each
65
+ repository brings is its `only_here` features; one issue per author in their own repository).
66
+
67
+ Live check on "sync Claude Code sessions across machines": 233 repositories, leader
68
+ tawanorg/claude-sync (320 stars, Go, R2 + end-to-end encryption), ~40 at 2–13 stars with disjoint
69
+ backends (Drive, SSH, Syncthing, Tailscale, Obsidian, git vault, LAN). Early mistakes fixed: queries
70
+ from stop-word-stripped phrases were too weak (now product names and distinctive tokens); cluster
71
+ ordered by similarity put 2-star repos above the leader (now stars); base chosen by recency picked a
72
+ fresh fork over the leader (now living leader); default `max_stars=200` excluded the leader (now
73
+ none).
74
+
75
+ GitHub's Acceptable Use Policies (read 2026-11-08) prohibit "automated excessive bulk activity",
76
+ "unsolicited advertising or solicitation" and "excessive bulk content in issues". The limits are
77
+ code, not advice: 3–15 living repositories per proposal, 10 issues a day, 3 s pacing, a ledger so
78
+ no repository is asked twice, archived and issues-disabled repositories skipped, the plan inline or
79
+ at a URL the user owns (no placeholder links in anything sent), opened only on the user's explicit
80
+ yes from the user's own account. 74 tests.
81
+
82
+ Independent review of the layer (same day) found the engine confidently wrong on ordinary inputs:
83
+ product-name mentions counted as overlap ("a Claude Code plugin to back up sessions" → claude-mem,
84
+ 114k stars, "already won"); core query words picked by length ("closed-contour" over "nl2sql" → "this
85
+ is new" for the most crowded field on GitHub); capped, star-sorted counts presented as medians; a
86
+ failed search reported as novelty; `max_stars` hiding the leader. On the merge side: no cluster
87
+ bound, a placeholder link in every public issue, the user's own and 3k-star repositories asked,
88
+ approval not bound to the texts shown. All fixed; the fixes are in the tests. Three rules came out
89
+ of it: relevance is measured on job words only, with all of them required for a short idea; a
90
+ cluster is reported with its search total and "at least" when capped; an empty cluster next to a
91
+ related field says "the parts exist", never "new". Claude Code plugin added (`plugin/`) so the check
92
+ runs before the agent writes the first line.
93
+
94
+ ## 2026-11-08, analogues checked again
95
+
96
+ GitHub topic `idea-validation` (8 repositories) and web search: `mnemox-ai/idea-reality-mcp` (created
97
+ 2026-02-24, 830 stars, maintenance mode since 2026-08) scores an idea against GitHub, HN, npm, PyPI,
98
+ Stack Overflow and lists similar repositories with pivot hints; `Smartulf123/check-before-you-build`
99
+ (2026-10, 0 stars) is an agent skill that writes "what exists, where the gap is". Neither builds a
100
+ feature matrix, proposes a merge to the authors, or finds the people. Nearest for people:
101
+ ResearcherCollab, CollabFinder (sites with manual profiles), openalex-research-mcp (co-authorship
102
+ data). The section "Before you build it" was renamed "Don't build it alone" to stop sharing a name
103
+ with a stranger's project and to say what is different: whoelse starts where idea checkers stop.
104
+ Searched in English only, GitHub and the open web; closed products and other languages not covered.
105
+
106
+ ## 2026-11-08, first live run on the author's profile (reported from his machine)
107
+
108
+ The list was dominated by one lab (Emory) that shared a single OpenAlex topic with the author,
109
+ "Topic Modeling", a bucket that holds half of NLP. Two causes: the pool was seeded with 100 works
110
+ from each of the five top topics, bucket included; and topics were scored without document
111
+ frequency, so a bucket counted as much as a specific topic, with recency (up to 0.2) added on top.
112
+ Fixes, mirrored from what keywords already had: topic document frequency over the pool and damping
113
+ of the known bucket topics; the pool is seeded from the author's specific topics only (two of
114
+ them), with more keyword queries instead; recency multiplies overlap rather than adding to it;
115
+ the gate needs a shared keyword, a keyword-search hit, a card or a specific topic, and a score
116
+ above 0.05. A keyword-search hit with no OpenAlex keywords counts as one shared keyword, so arXiv
117
+ preprints found on the author's own terms keep their place.
118
+
119
+ Second live run (same day, from the author's machine) showed the first fix overshot: narrowing
120
+ the topic seed from five to two dropped the people who were only reachable through the third
121
+ topic (they were not demoted, they were no longer found), and single-word keywords sent as
122
+ literal queries to GitHub and Hugging Face returned VPN configs, an archiver and a game, each
123
+ pushed today and lifted by freshness above real scientists. Corrected: the seed is all specific
124
+ (non-bucket) topics up to five, since the df damping in score() is what makes buckets harmless;
125
+ only phrases of two or more words go to code, model and preprint search, and a hit must carry the
126
+ phrase contiguously in its name, description or tags; the keyword-search floor (0.15) earns no
127
+ freshness. Lesson kept: a unit test on score() does not catch a loss at the discovery stage;
128
+ the live run does.
129
+
130
+ ## 2026-11-08, distribution
131
+
132
+ Vladimir's constraint, stated plainly: posting on his own channels has never moved anything, for any
133
+ of his products. So the channels used are the ones where other people's audiences or the product
134
+ itself bring the reader: a pull request to awesome-mcp-servers (Research section, #18892), a listing
135
+ request on mcp.so (#6933), a release pipeline that publishes to PyPI by trusted publishing and to the
136
+ official MCP Registry by GitHub OIDC on one tag (the user must register the pending publisher on PyPI
137
+ once), six cluster pages under docs/clusters generated from real runs (pages people search for, each
138
+ pointing back), and the product's own hands: propose_merge rounds to real authors, 10 issues a day,
139
+ every text shown to the user first. Not done, by rule: Glama and Smithery need an account sign-in
140
+ (his action); awesome-agent-skills refuses new skills without usage (submit in a month). The
141
+ ceiling in this niche is known: idea-reality-mcp, 830 stars in eight months.
142
+
143
+ Preparing the first round exposed four more things in the matcher and the plan: a cluster over 15
144
+ is split into a batch (the living leader plus the most recently active) rather than refused; a
145
+ sender who is not one of the authors says so in the first line ("Who is asking"); what a repository
146
+ brings is its own description when no feature is unique, never an invented "working implementation";
147
+ the merge target is the base repository, not a repository that does not exist. In the matcher: the
148
+ verb of the idea is required but not counted (a note-UID generator is not a site generator), a
149
+ distinctive job word must match (sessions-to-a-wearable is about the wearable), technical tokens
150
+ (pii, nl2sql) are sharp for membership but cannot alone name a related repository ("mcp server"),
151
+ and no merge is proposed where a 1000+-star leader has decided the field.
whoelse-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vladimir Beskorovainyi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
whoelse-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,313 @@
1
+ Metadata-Version: 2.5
2
+ Name: whoelse
3
+ Version: 0.1.0
4
+ Summary: Who else is working on what you're working on? An MCP server that finds them, works out what you could build together, and drafts the first message.
5
+ Project-URL: Homepage, https://github.com/beskvladimir-create/whoelse
6
+ Author: Vladimir Beskorovainyi
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Keywords: agents,arxiv,collaboration,github,huggingface,mcp,openalex,research
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Scientific/Engineering
13
+ Requires-Python: >=3.10
14
+ Requires-Dist: httpx>=0.27
15
+ Requires-Dist: mcp>=1.2
16
+ Requires-Dist: pydantic>=2
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
19
+ Requires-Dist: pytest>=8; extra == 'dev'
20
+ Description-Content-Type: text/markdown
21
+
22
+ # whoelse
23
+
24
+ <!-- mcp-name: io.github.beskvladimir-create/whoelse -->
25
+
26
+ **Don't build it alone.**
27
+
28
+ Ask an agent to build something and it will, for the 21st time. Somewhere, twenty people already
29
+ built it, each got ten stars, and three more are working on the same thing right now. None of them
30
+ know each other.
31
+
32
+ whoelse puts one call in front of the first line of code: what already exists, who won, what nobody
33
+ has, and then the step no other tool takes: a plan to merge the small ones into one project with
34
+ every author on it, or the person whose current work overlaps yours, with what the two of you could
35
+ build and the first message drafted. Nothing is sent without you.
36
+
37
+ Runs inside Claude, Cursor, Codex or any MCP client. No sign-up, no profile to fill in, no server. Free.
38
+
39
+ ```bash
40
+ pip install git+https://github.com/beskvladimir-create/whoelse
41
+ ```
42
+
43
+ ![whoelse: what the agent says before writing a line](docs/demo.png)
44
+
45
+ ---
46
+
47
+ ## The problem
48
+
49
+ Nobody is working alone on purpose. It just turns out that way: you publish, nothing happens, you go back to work. The person who would have cited you, tried your code, co-written the next paper with you, is two time zones away and has never heard your name. Discovery runs on conferences and luck, and most people get neither.
50
+
51
+ whoelse replaces luck with a lookup, and then does something with what it finds.
52
+
53
+ ## Don't build it alone
54
+
55
+ Idea checkers exist ([idea-reality-mcp](https://github.com/mnemox-ai/idea-reality-mcp) scores an
56
+ idea against GitHub, HN and npm and stops at "here are similar projects"). whoelse starts where they
57
+ stop. Ask your agent to build a tool:
58
+
59
+ > Build me a CLI that syncs Claude Code sessions across machines.
60
+
61
+ ```
62
+ "a CLI that syncs Claude Code sessions across machines" exists at least 40 times. The leader is
63
+ tawanorg/claude-sync (320 stars, last pushed 2026-10-06); the other 39 have a median of 1.
64
+ Between them: end-to-end encryption, Cloudflare R2, git-backed sync, Google Drive, LAN sync,
65
+ Codex sessions, backup before the 30-day deletion. None of the 40 has a terminal UI, hooks,
66
+ an Obsidian export, mobile, or cost tracking.
67
+
68
+ Options: contribute the missing backend to claude-sync; build only what nobody has; or propose a
69
+ merge to the small ones (propose_merge).
70
+ ```
71
+
72
+ (Real output, 2026-11-08, unauthenticated GitHub search.)
73
+
74
+ That is `find_duplicates`. It searches GitHub for the job the tool does (not the product it serves),
75
+ keeps what is actually the same thing, ranks it, and builds a feature matrix: who has what, what only one of them has, what none of them
76
+ has. The verdict comes first, in one sentence. Hundreds of hours of rebuilding the same thing, and
77
+ the tokens spent on it, stop here.
78
+
79
+ `propose_merge` goes one step further. For a cluster of small duplicates it writes the merge plan
80
+ (the living leader as the base; what each repository brings, from its own README; every author a
81
+ maintainer with write access; nothing deleted; a release date) and the text of one issue for each
82
+ author, in their own repository, where they already read. The issues go out only after you have
83
+ read them and said yes, from your GitHub account, all at once, so no author is asked to join
84
+ someone else's project: all of them are asked to join one.
85
+
86
+ GitHub's acceptable use forbids bulk unsolicited content, and so does common sense, so the limits
87
+ are in the code: 3 to 15 living repositories per proposal, at most 10 issues a day, 3 seconds
88
+ apart, never twice to the same repository (a local ledger remembers), never to an archived, forked, inactive or
89
+ organisation-owned repository, one with issues turned off, one with 1000+ stars, or your own. One proposal is a conversation; forty is a mailing.
90
+
91
+ ### Put it in front of the agent
92
+
93
+ `plugin/` is a Claude Code plugin (MCP server plus a `dont-build-it-alone` skill) that makes the agent
94
+ call `find_duplicates` before it starts building anything the user describes. For Cursor, Codex and
95
+ other MCP clients the same skill text goes into the rules file. The user sees what exists before the
96
+ first line is generated, which is the only moment the information is worth anything.
97
+
98
+ Real runs, one page per idea, live in
99
+ [awesome-already-built](https://github.com/beskvladimir-create/awesome-already-built): session sync
100
+ for Claude Code, arXiv MCP servers, PII anonymization for LLMs, token-cost dashboards, Obsidian site
101
+ generators, DICOM in Rust. Add an idea there with an issue; fix your row with a pull request.
102
+
103
+ ## How it connects strangers
104
+
105
+ Finding people is the easy half. whoelse is built around the hard half: two people who have never
106
+ heard of each other end up working on one thing, fast.
107
+
108
+ **1. The work starts before the first message.** `start_joint_work` builds a repository with the
109
+ paper outline, section 1 drafted from both sides' published abstracts, a comparison table holding
110
+ the numbers each side already published, a reproduction script pointing at both codebases, both
111
+ names on the byline, and a 14-day plan. The other person receives a link to a third of a finished
112
+ work. Saying yes is opening an issue titled "in". Saying no is ignoring it: after 14 days you
113
+ finish alone and cite them.
114
+
115
+ **2. Mutual matching without any letters.** `publish_request` puts what you want to build into an
116
+ open registry (one JSON file per person, in a public GitHub repository; no account with us, no
117
+ server). It publishes your name and email, so your agent shows you the file and asks before it
118
+ goes. Anyone who installs whoelse with the same problem is matched to you. When both sides want the
119
+ same format on the same problem, one watcher (the side whose name sorts first) creates the
120
+ repository, invites the other, and emails both; the other watcher sees the repository appear and
121
+ confirms, or takes over after three days of silence.
122
+
123
+ **3. Nobody falls out of the queue.** If there is no match today, whoelse says so plainly:
124
+
125
+ > Your request is published. 37 people are waiting in the network, none on text-to-SQL yet. When
126
+ > one joins, the work starts by itself and a link goes to you@example.org. Nothing to do; just
127
+ > don't remove whoelse.
128
+
129
+ `whoelse-watch --loop 6h` keeps checking. The link arrives by email (your own SMTP, or GitHub's own
130
+ notification when the repository is created and you are invited).
131
+
132
+ **4. Strangers, by design.** People you already publish with are listed separately and never
133
+ proposed. Requests that share an id with yours are skipped. Complementary assets score higher:
134
+ your code against their data, their paper against your system.
135
+
136
+ **5. Nobody's name goes public on the strength of a file.** A registry file is data written by a
137
+ stranger. It must fit a strict schema; the registry's CI merges it only if `ids.github` is the
138
+ login that opened the pull request and the file is not someone else's; the watcher acts on it only
139
+ if that GitHub profile's display name is the name in the file. That proves the file belongs to that
140
+ account, not that the account is the researcher it names, so the joint repository is created
141
+ **private**, the account is invited, and it goes public only after they accept and say "in". If
142
+ they never do, you finish alone and publish without their name, citing their work. A repository
143
+ that already exists is never overwritten.
144
+
145
+ ## What you get
146
+
147
+ Ask your agent:
148
+
149
+ > Load my profile: Vladimir Beskorovainyi, ORCID 0009-0004-7005-6242. Who else is working on this?
150
+
151
+ ```
152
+ 25 people are working on what Vladimir Beskorovainyi is working on (personal papers; archives; text classification).
153
+ 4 can be written to today.
154
+
155
+ 0. Angelo La Gorga (Universidad Carlos III de Madrid): same problem: personal papers; active 2026-09. reach: email
156
+ 1. Fabian Karl (Universität Ulm): same topic: computational and text analysis, text classification; active 2026-01. reach: email
157
+ 2. Lukas Galke (University of Southern Denmark): same topic: text classification; active 2026-01. reach: email
158
+ ```
159
+
160
+ > Start a comparison note with Ada Example (illustration; the names below are made up).
161
+
162
+ ```
163
+ Repository: github.com/you/you-example-text-to-sql
164
+ paper/paper.md outline; section 1 drafted from both abstracts; table with published numbers
165
+ repro/run.py both methods, same data, same metric; each side fills its half
166
+ PLAN.md 14 days to a preprint
167
+ CITATION.cff both names
168
+ Send this: three sentences, the link, one yes/no question. To: ada@example.org (from her whoelse card)
169
+ ```
170
+
171
+ > Publish my request: a comparison note on text-to-SQL for closed enterprise data, by December.
172
+
173
+ ```
174
+ Your request is published. 2 people are waiting in the network; 1 wants what you want: Ana Example
175
+ (illustration), text-to-sql, has a dataset you don't. Joint work can start now.
176
+ ```
177
+
178
+ ## How it finds people
179
+
180
+ Three directions at once, then merged into people:
181
+
182
+ | direction | source | what it catches |
183
+ |---|---|---|
184
+ | papers | OpenAlex keywords and topics; arXiv for preprints OpenAlex hasn't indexed yet | who published on your exact problem in the last 24 months |
185
+ | code | GitHub repository search | who is building it |
186
+ | models and data | Hugging Face Hub | who released weights or a dataset (quantisations and repacks are filtered out) |
187
+
188
+ A GitHub login, a Hugging Face account and an OpenAlex author become one person only when a second signal says so: the same affiliation, a link from their paper to that account, the same website. A shared name alone keeps them apart, flagged as possible namesakes, so one person's email never lands next to another's work. Organisations (a company's GitHub, a lab's Hugging Face) are recognised and left out. Authors who link their own code in an arXiv comment are joined automatically, including you: give whoelse your name and it usually finds your handles itself.
189
+
190
+ If several people share your name, whoelse does not guess. It shows you the namesakes and asks for an ORCID or an affiliation.
191
+
192
+ A third reach channel, GitHub user search by full name, is used only when it returns exactly one account whose repositories are about the same subject; otherwise it is ignored. On real data it finds roughly one in three researchers who left nothing on ORCID.
193
+
194
+ ## How it reaches them
195
+
196
+ Only through what the person published about themselves, and every contact says where it came from:
197
+
198
+ - ORCID: public email, personal site, GitHub, Scholar, LinkedIn (limited-visibility emails are never read)
199
+ - GitHub profile: public email, website
200
+ - Their own website: a whoelse card, if they have one
201
+
202
+ arXiv submitter emails are never touched. arXiv's terms forbid using them for unsolicited contact, and we don't need them.
203
+
204
+ ## The network
205
+
206
+ A public GitHub repository, `beskvladimir-create/whoelse-network`, with one JSON file per person
207
+ under `people/`. Your agent opens the pull request (with a `GITHUB_TOKEN` that has `public_repo`
208
+ scope), or writes the file and tells you where to put it. Calling `publish_request` again renews
209
+ or updates your file on the same branch. Requests expire after three months. Reading needs no
210
+ account. There is no server and nothing to sign up for; the repository is the directory. The
211
+ registry's own CI and README are in `registry/` in this repository.
212
+
213
+ `whoelse-watch` reads it fresh every pass (the registry is never served from cache), matches your
214
+ request against everyone else's, and when two people want the same format on the same problem it
215
+ builds the workspace, creates the repository, invites the other side, and emails both; once per
216
+ pair, with state saved after every step. Run it from cron or launchd:
217
+
218
+ ```
219
+ 0 */6 * * * whoelse-watch
220
+ ```
221
+
222
+ ## The card: connected mode without a server
223
+
224
+ Put this on your own site at `/.well-known/whoelse.json`:
225
+
226
+ ```json
227
+ {
228
+ "name": "Ada Example",
229
+ "working_on": ["text-to-SQL on open-weight models", "schema linking"],
230
+ "open_to": ["co-author", "joint benchmark", "talk together"],
231
+ "contact": "ada@example.org",
232
+ "languages": ["en", "pt"],
233
+ "updated": "2026-11-07"
234
+ }
235
+ ```
236
+
237
+ Anyone running whoelse now sees you as **connected**: reachable, and open to exactly what you said. When both sides have a card, both of you are one `joint_work_brief` away from the same proposal; sending it to both at once is on the roadmap. No registry, no account, no central anything. The web is the directory. `make_card` writes yours.
238
+
239
+ ## Your people
240
+
241
+ Once you've decided someone is one of yours (`add_peer`), whoelse watches what they ship and tells you when there is something to support: a repo to try and star, a paper to cite or argue with, a model to run on your data and report back. It never stars, follows or likes anything for you. GitHub names automated starring and following as rank abuse, and a circle that fakes its own signal is worth nothing to the people in it.
242
+
243
+ ## Tools
244
+
245
+ | tool | what |
246
+ |---|---|
247
+ | `load_profile` | your profile from OpenAlex, arXiv, GitHub, Hugging Face, ORCID |
248
+ | `find_overlaps` | people whose recent work overlaps yours, ranked, with reasons and public contacts |
249
+ | `joint_work_brief` | one person: the evidence, what each side has, formats ranked by fit and effort, venues in common |
250
+ | `draft_outreach` | facts and structure for the first message; your agent writes it, you send it |
251
+ | `add_peer`, `remove_peer`, `whats_new_from_peers` | your people and what they shipped this month |
252
+ | `find_duplicates` | before building: what exists, who won, what nobody has |
253
+ | `propose_merge` | a merge plan for a cluster of duplicates and one issue per author (sent only on your yes) |
254
+ | `publish_request` | join the network: what you want to build, with whom, by when |
255
+ | `start_joint_work` | a repository with a third of the work done and both names on it |
256
+ | `make_card` | your `/.well-known/whoelse.json` |
257
+ | `list_known` | profiles and peers on this machine |
258
+
259
+ ## Install
260
+
261
+ ```bash
262
+ pip install whoelse # or: pip install git+https://github.com/beskvladimir-create/whoelse
263
+ ```
264
+
265
+ Claude Code: `claude mcp add whoelse -- whoelse`
266
+
267
+ Claude Desktop, Cursor, Codex and others, in the MCP config:
268
+
269
+ ```json
270
+ { "mcpServers": { "whoelse": { "command": "whoelse" } } }
271
+ ```
272
+
273
+ Optional environment:
274
+
275
+ | variable | effect |
276
+ |---|---|
277
+ | `WHOELSE_OPENALEX_KEY` | free key from openalex.org/settings/api; without it you share a small per-IP daily budget |
278
+ | `WHOELSE_MAILTO` | your email for OpenAlex's polite pool; sent nowhere else |
279
+ | `GITHUB_TOKEN` | raises GitHub search limits (any scope); `public_repo` scope is needed for `publish_request`, `start_joint_work` and the watcher |
280
+ | `WHOELSE_SMTP_HOST`, `_PORT`, `_USER`, `_PASS`, `_FROM` | the watcher's email, sent from your own address; without them, notifications land in `~/.whoelse/inbox/` |
281
+ | `WHOELSE_HOME` | where profiles, peers and cache live (default `~/.whoelse`) |
282
+
283
+ ## What it will not do
284
+
285
+ - Send a letter for you. Drafts are yours to send, from your own address, one person at a time.
286
+ The only automatic messages are the watcher's: to you, and to a verified stranger, once, with a
287
+ public repository link, after you joined the network and confirmed what gets published.
288
+ - Use a contact the person did not publish themselves (their ORCID, their GitHub, their own card,
289
+ their own registry file).
290
+ - Star, follow, like or post on your behalf.
291
+ - Keep anything about you anywhere but your machine, except the registry file you confirmed and
292
+ the joint repositories you asked for.
293
+
294
+ ## First run on your own name
295
+
296
+ ```bash
297
+ WHOELSE_MAILTO=you@example.org python -m whoelse.scripts.first_run "Your Name" --orcid 0000-0000-0000-0000
298
+ ```
299
+
300
+ Prints the people, the reasons, the best format for each, and how to reach them; saves everything to `whoelse-first-run.json`. Nothing is sent.
301
+
302
+ ## Develop
303
+
304
+ ```bash
305
+ git clone https://github.com/beskvladimir-create/whoelse && cd whoelse
306
+ pip install -e ".[dev]"
307
+ pytest # offline, on recorded fixtures
308
+ WHOELSE_FIXTURES=tests/fixtures python -m whoelse.server # offline demo server
309
+ ```
310
+
311
+ Sources: [OpenAlex](https://openalex.org) (CC0), [arXiv](https://arxiv.org) (CC0 metadata), [ORCID](https://orcid.org) public API, [GitHub](https://docs.github.com/en/rest), [Hugging Face Hub](https://huggingface.co/docs/hub/api). All keyless.
312
+
313
+ MIT.