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.
- whoelse-0.1.0/.github/PUBLISH.md +23 -0
- whoelse-0.1.0/.github/workflows/release.yml +38 -0
- whoelse-0.1.0/.github/workflows/test.yml +15 -0
- whoelse-0.1.0/.gitignore +6 -0
- whoelse-0.1.0/.well-known/whoelse.json +21 -0
- whoelse-0.1.0/CHANGELOG.md +20 -0
- whoelse-0.1.0/DECISIONS.md +151 -0
- whoelse-0.1.0/LICENSE +21 -0
- whoelse-0.1.0/PKG-INFO +313 -0
- whoelse-0.1.0/README.md +292 -0
- whoelse-0.1.0/docs/LAUNCH.md +66 -0
- whoelse-0.1.0/docs/clusters/README.md +10 -0
- whoelse-0.1.0/docs/clusters/arxiv-mcp-servers.md +54 -0
- whoelse-0.1.0/docs/clusters/claude-code-session-sync.md +54 -0
- whoelse-0.1.0/docs/clusters/dicom-rust.md +31 -0
- whoelse-0.1.0/docs/clusters/llm-token-cost-dashboards.md +22 -0
- whoelse-0.1.0/docs/clusters/obsidian-static-site-generators.md +31 -0
- whoelse-0.1.0/docs/clusters/pii-anonymization-for-llms.md +21 -0
- whoelse-0.1.0/docs/demo.png +0 -0
- whoelse-0.1.0/plugin/.claude-plugin/plugin.json +11 -0
- whoelse-0.1.0/plugin/README.md +18 -0
- whoelse-0.1.0/plugin/skills/dont-build-it-alone/SKILL.md +26 -0
- whoelse-0.1.0/pyproject.toml +40 -0
- whoelse-0.1.0/registry/.github/workflows/check.yml +65 -0
- whoelse-0.1.0/registry/README.md +14 -0
- whoelse-0.1.0/server.json +26 -0
- whoelse-0.1.0/src/whoelse/__init__.py +3 -0
- whoelse-0.1.0/src/whoelse/brief.py +168 -0
- whoelse-0.1.0/src/whoelse/config.py +65 -0
- whoelse-0.1.0/src/whoelse/duplicates.py +770 -0
- whoelse-0.1.0/src/whoelse/http.py +159 -0
- whoelse-0.1.0/src/whoelse/match.py +638 -0
- whoelse-0.1.0/src/whoelse/models.py +100 -0
- whoelse-0.1.0/src/whoelse/network.py +511 -0
- whoelse-0.1.0/src/whoelse/peers.py +123 -0
- whoelse-0.1.0/src/whoelse/profile.py +348 -0
- whoelse-0.1.0/src/whoelse/scripts/__init__.py +0 -0
- whoelse-0.1.0/src/whoelse/scripts/first_run.py +67 -0
- whoelse-0.1.0/src/whoelse/server.py +499 -0
- whoelse-0.1.0/src/whoelse/sources/__init__.py +2 -0
- whoelse-0.1.0/src/whoelse/sources/arxiv.py +103 -0
- whoelse-0.1.0/src/whoelse/sources/card.py +80 -0
- whoelse-0.1.0/src/whoelse/sources/github.py +135 -0
- whoelse-0.1.0/src/whoelse/sources/huggingface.py +96 -0
- whoelse-0.1.0/src/whoelse/sources/openalex.py +181 -0
- whoelse-0.1.0/src/whoelse/sources/orcid.py +95 -0
- whoelse-0.1.0/src/whoelse/watch.py +308 -0
- whoelse-0.1.0/src/whoelse/workspace.py +352 -0
- whoelse-0.1.0/tests/conftest.py +24 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-anonymization.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-citizen_appeals.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-nl2sql.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-open-weight_models.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-pii.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-public_administration.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-qwen.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-schema_linking.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-text-to-sql.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_all-text_classification.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_au_ana_ferreira.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_au_li_wei.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_au_vladimir_beskorovainyi.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_au_yusuf_demir.json +3 -0
- whoelse-0.1.0/tests/fixtures/arxiv_au_yuyu_luo.json +3 -0
- whoelse-0.1.0/tests/fixtures/card_amine.io.json +17 -0
- whoelse-0.1.0/tests/fixtures/card_sqlbot.dev.json +1 -0
- whoelse-0.1.0/tests/fixtures/github_me.json +3 -0
- whoelse-0.1.0/tests/fixtures/github_repos_anaferreira.json +18 -0
- whoelse-0.1.0/tests/fixtures/github_repos_apena-gamedev.json +19 -0
- whoelse-0.1.0/tests/fixtures/github_repos_besk-tech.json +38 -0
- whoelse-0.1.0/tests/fixtures/github_repos_notluo.json +1 -0
- whoelse-0.1.0/tests/fixtures/github_repos_ppapotti.json +18 -0
- whoelse-0.1.0/tests/fixtures/github_repos_ydemir.json +1 -0
- whoelse-0.1.0/tests/fixtures/github_search_anonymization.json +3 -0
- whoelse-0.1.0/tests/fixtures/github_search_citizen_appeals.json +3 -0
- whoelse-0.1.0/tests/fixtures/github_search_claude_code_backup.json +53 -0
- whoelse-0.1.0/tests/fixtures/github_search_claude_code_plugin_backup_conversations.json +53 -0
- whoelse-0.1.0/tests/fixtures/github_search_claude_code_plugin_backup_sessions.json +53 -0
- whoelse-0.1.0/tests/fixtures/github_search_claude_code_plugin_snapshot_sessions.json +53 -0
- whoelse-0.1.0/tests/fixtures/github_search_claude_code_sessions.json +53 -0
- whoelse-0.1.0/tests/fixtures/github_search_claude_code_sync_sessions.json +158 -0
- whoelse-0.1.0/tests/fixtures/github_search_claude_code_wearable.json +158 -0
- whoelse-0.1.0/tests/fixtures/github_search_nl2sql.json +3 -0
- whoelse-0.1.0/tests/fixtures/github_search_pii.json +3 -0
- whoelse-0.1.0/tests/fixtures/github_search_public_administration.json +3 -0
- whoelse-0.1.0/tests/fixtures/github_search_qwen.json +3 -0
- whoelse-0.1.0/tests/fixtures/github_search_schema_linking.json +3 -0
- whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_conversations_machines.json +158 -0
- whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_conversations_wearable.json +158 -0
- whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_sessions_devices.json +158 -0
- whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_sessions_machines.json +158 -0
- whoelse-0.1.0/tests/fixtures/github_search_sync_claude_code_sessions_wearable.json +158 -0
- whoelse-0.1.0/tests/fixtures/github_search_synchronize_claude_code_sessions_machines.json +158 -0
- whoelse-0.1.0/tests/fixtures/github_search_synchronize_claude_code_sessions_wearable.json +158 -0
- whoelse-0.1.0/tests/fixtures/github_search_text-to-sql.json +36 -0
- whoelse-0.1.0/tests/fixtures/github_search_text_classification.json +3 -0
- whoelse-0.1.0/tests/fixtures/github_search_todo_language_rust.json +53 -0
- whoelse-0.1.0/tests/fixtures/github_search_todo_rust.json +53 -0
- whoelse-0.1.0/tests/fixtures/github_user_anaferreira.json +10 -0
- whoelse-0.1.0/tests/fixtures/github_user_besk-tech.json +9 -0
- whoelse-0.1.0/tests/fixtures/github_user_kmori.json +10 -0
- whoelse-0.1.0/tests/fixtures/github_user_notluo.json +10 -0
- whoelse-0.1.0/tests/fixtures/github_user_ppapotti.json +9 -0
- whoelse-0.1.0/tests/fixtures/github_user_sqlbot.json +9 -0
- whoelse-0.1.0/tests/fixtures/github_user_ydemir.json +10 -0
- whoelse-0.1.0/tests/fixtures/github_users_alejandro_pe/303/261a.json +8 -0
- whoelse-0.1.0/tests/fixtures/github_users_amine_mhedhbi.json +4 -0
- whoelse-0.1.0/tests/fixtures/github_users_david_graus.json +14 -0
- whoelse-0.1.0/tests/fixtures/github_users_li_wei.json +14 -0
- whoelse-0.1.0/tests/fixtures/github_users_nikhil_rao.json +14 -0
- whoelse-0.1.0/tests/fixtures/github_users_paolo_papotti.json +8 -0
- whoelse-0.1.0/tests/fixtures/hf_dataset_search_anonymization.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_dataset_search_citizen_appeals.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_dataset_search_nl2sql.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_dataset_search_pii.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_dataset_search_public_administration.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_dataset_search_qwen.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_dataset_search_schema_linking.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_dataset_search_text-to-sql.json +13 -0
- whoelse-0.1.0/tests/fixtures/hf_dataset_search_text_classification.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_model_search_anonymization.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_model_search_citizen_appeals.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_model_search_nl2sql.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_model_search_pii.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_model_search_public_administration.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_model_search_qwen.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_model_search_schema_linking.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_model_search_text-to-sql.json +14 -0
- whoelse-0.1.0/tests/fixtures/hf_model_search_text_classification.json +1 -0
- whoelse-0.1.0/tests/fixtures/hf_user_amine-io.json +5 -0
- whoelse-0.1.0/tests/fixtures/hf_user_defog.json +5 -0
- whoelse-0.1.0/tests/fixtures/hf_user_sqlbot.json +1 -0
- whoelse-0.1.0/tests/fixtures/network_ana-ferreira.json +35 -0
- whoelse-0.1.0/tests/fixtures/network_evil.json +16 -0
- whoelse-0.1.0/tests/fixtures/network_expired.json +16 -0
- whoelse-0.1.0/tests/fixtures/network_kenji-mori.json +32 -0
- whoelse-0.1.0/tests/fixtures/network_repo_beskvladimir-create_whoelse-network.json +3 -0
- whoelse-0.1.0/tests/fixtures/network_tree_beskvladimir-create_whoelse-network.json +31 -0
- whoelse-0.1.0/tests/fixtures/network_yusuf-demir.json +33 -0
- whoelse-0.1.0/tests/fixtures/network_yuyu-luo.json +32 -0
- whoelse-0.1.0/tests/fixtures/openalex_author_orcid_0000-0000-0000-9999.json +1 -0
- whoelse-0.1.0/tests/fixtures/openalex_author_orcid_0000-0001-0000-0001.json +12 -0
- whoelse-0.1.0/tests/fixtures/openalex_author_orcid_0000-0001-9530-3327.json +1 -0
- whoelse-0.1.0/tests/fixtures/openalex_author_orcid_0000-0002-2222-3333.json +12 -0
- whoelse-0.1.0/tests/fixtures/openalex_authors_li_wei.json +48 -0
- whoelse-0.1.0/tests/fixtures/openalex_authors_vladimir_beskorovainyi.json +23 -0
- whoelse-0.1.0/tests/fixtures/openalex_authors_yusuf_demir.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_authors_yuyu_luo.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_author_A5000000001.json +341 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_author_A5000000050.json +121 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_author_A5000000102.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_kw_citizen-appeals_p1.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_kw_deep-learning_p1.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_kw_enterprise-bi_p1.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_kw_open-weight-models_p1.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_kw_public-administration_p1.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_kw_schema-linking_p1.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_kw_text-classification_p1.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_kw_text-to-sql_p1.json +321 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_search_anonymization.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_search_citizen_appeals.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_search_nl2sql.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_search_pii.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_search_public_administration.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_search_qwen.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_search_schema_linking.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_search_text-to-sql.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_search_text_classification.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_topic_T10181_p1.json +281 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_topic_T10992_p1.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_topic_T11714_p1.json +3 -0
- whoelse-0.1.0/tests/fixtures/openalex_works_topic_T12345_p1.json +197 -0
- whoelse-0.1.0/tests/fixtures/orcid_person_0000-0001-0000-0001.json +8 -0
- whoelse-0.1.0/tests/fixtures/orcid_person_0000-0001-1111-2222.json +13 -0
- whoelse-0.1.0/tests/fixtures/orcid_person_0000-0002-0000-0001.json +24 -0
- whoelse-0.1.0/tests/fixtures/orcid_person_0000-0002-2222-3333.json +8 -0
- whoelse-0.1.0/tests/fixtures/orcid_person_0000-0002-9035-7045.json +19 -0
- whoelse-0.1.0/tests/fixtures/orcid_person_0000-0003-0651-4128.json +19 -0
- whoelse-0.1.0/tests/fixtures/orcid_person_0009-0000-9342-5144.json +19 -0
- whoelse-0.1.0/tests/make_fixtures.py +375 -0
- whoelse-0.1.0/tests/test_duplicates.py +249 -0
- whoelse-0.1.0/tests/test_network.py +320 -0
- whoelse-0.1.0/tests/test_regressions.py +379 -0
- 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
|
whoelse-0.1.0/.gitignore
ADDED
|
@@ -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
|
+

|
|
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.
|