humanbottasks 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.
@@ -0,0 +1,6 @@
1
+ .venv/
2
+ __pycache__/
3
+ dist/
4
+ tasks.db
5
+ *.log
6
+ uv.lock
@@ -0,0 +1,69 @@
1
+ # Forum-/Community-Posts (fertig zum Copy-Paste)
2
+
3
+ Englisch, weil die Zielgruppe (AI-Builder) englischsprachig ist.
4
+ Posten braucht deine Accounts — die Texte sind einsatzbereit.
5
+
6
+ ---
7
+
8
+ ## Reddit r/MCP
9
+
10
+ **Title:** I built humanbottasks — delegate anything your agent can't do to a real human, over MCP
11
+
12
+ **Body:**
13
+ Two tools. That's the whole API:
14
+
15
+ - `request_human_task(type, description, max_price)` — verification, physical_action, subjective_judgment, ground_truth_labeling, prove_human
16
+ - `get_task_status(task_id)` — poll for the result
17
+
18
+ Install: `uvx --from git+https://github.com/humanbottasks/humanbottasks humanbottasks`
19
+
20
+ Works over stdio (Claude Desktop, Cursor, Windsurf) and streamable-http (remote agents).
21
+
22
+ I built this because I kept hitting the same wall: agents confidently asserting things they couldn't verify, with no clean handoff for the parts only a human can do. The existing options either want me to wire up a marketplace account or bolt on a whole SDK — I wanted the thinnest possible thing that just works.
23
+
24
+ It's an MVP (SQLite queue, no payments yet — I fulfill tasks manually right now). Honest question for this sub: which task type actually matters to you? Where do your agents actually get stuck?
25
+
26
+ Repo: https://github.com/humanbottasks/humanbottasks
27
+
28
+ ---
29
+
30
+ ## Reddit r/LocalLLaMA
31
+
32
+ **Title:** Local agents can now call a human — humanbottasks (MCP, stdio, no cloud)
33
+
34
+ **Body:**
35
+ If you run local agents (Ollama/LM Studio + LangChain/CrewAI), here's a human-in-the-loop fallback that's just an MCP server on your own machine. No cloud account, no hosted service.
36
+
37
+ - stdio (spawn it as a subprocess, same as any MCP server) + streamable-http for remote
38
+ - Two tools: request_human_task / get_task_status
39
+ - SQLite queue, you (or anyone) fulfill via a one-line CLI
40
+
41
+ Install: `uvx --from git+https://github.com/humanbottasks/humanbottasks humanbottasks`
42
+
43
+ Why this matters for local agents specifically: local models are even worse at verification and physical-world actions than frontier models, and they can't buy things or pick up a phone at all. A local agent that can delegate the "actually check this" part to a human is much more useful.
44
+
45
+ Repo: https://github.com/humanbottasks/humanbottasks
46
+
47
+ ---
48
+
49
+ ## X/Twitter (Thread, 3 Posts)
50
+
51
+ **Post 1:**
52
+ Your agent can't do everything. Now it can ask a human — over MCP, one line:
53
+ `uvx --from git+https://github.com/humanbottasks/humanbottasks humanbottasks`
54
+
55
+ **Post 2:**
56
+ Two tools: `request_human_task` and `get_task_status`. That's it. Verification, physical actions, subjective judgment, ground-truth labeling — delegate it to a real person, poll for the result. stdio + streamable-http.
57
+
58
+ **Post 3:**
59
+ Built this after watching agents confidently assert things they couldn't verify, with no clean handoff for the human parts. Open source, MIT, works with Claude Desktop / Cursor / Windsurf / local agents.
60
+ https://github.com/humanbottasks/humanbottasks
61
+
62
+ ---
63
+
64
+ ## Discord (MCP / LangChain / n8n / Dify servers)
65
+
66
+ **Kurzer Blurb:**
67
+ > humanbottasks — human fallback for AI agents over MCP. Two tools (request_human_task / get_task_status), stdio + streamable-http, one-line install:
68
+ > `uvx --from git+https://github.com/humanbottasks/humanbottasks humanbottasks`
69
+ > MIT, works with Claude Desktop/Cursor/Windsurf and local agent frameworks.
@@ -0,0 +1,33 @@
1
+ # Show HN / Launch Post
2
+
3
+ Fertig zum Einfuegen (Show HN, X, Discord, Reddit r/MCP r/LocalLLaMA).
4
+
5
+ ---
6
+
7
+ **Show HN: humanbottasks — human fallback for AI agents over MCP**
8
+
9
+ Your agent can't do everything. When it needs to verify a fact, make a phone
10
+ call, buy or ship something, or judge whether text sounds natural, it can now
11
+ delegate that to a real human — over MCP, one line.
12
+
13
+ Two tools:
14
+ - `request_human_task(type, description, max_price)` — submit a task
15
+ - `get_task_status(task_id)` — poll for the result
16
+
17
+ Install:
18
+ uvx --from git+https://github.com/humanbottasks/humanbottasks humanbottasks
19
+
20
+ Works with Claude Desktop, Cursor, Windsurf (stdio) and remote agents
21
+ (streamable-http). Task types: verification, physical_action,
22
+ subjective_judgment, ground_truth_labeling, prove_human.
23
+
24
+ Why: models are great at reasoning and bad at anything that touches the
25
+ physical world or needs verified judgment. This is the thinnest possible
26
+ "human in the loop" — no SDK, just MCP, the protocol agents already speak.
27
+
28
+ I kept hitting the same wall: agents confidently asserting things they
29
+ couldn't verify, with no clean way to hand off the parts only a human can do.
30
+ So I built the handoff. Would love feedback — especially on which task types
31
+ matter most to you.
32
+
33
+ Repo: https://github.com/humanbottasks/humanbottasks
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 humanbottasks
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.
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.5
2
+ Name: humanbottasks
3
+ Version: 0.1.0
4
+ Summary: Human fallback for AI agents: delegate tasks a model can't do to a human, over MCP.
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: mcp<2
8
+ Description-Content-Type: text/markdown
9
+
10
+ # humanbottasks
11
+
12
+ Gemanagter Human-Service-Layer fuer AI-Agenten. Ein AI-Agent delegiert ueber MCP
13
+ eine Aufgabe, die er nicht selbst kann, an einen Menschen; der Mensch erledigt
14
+ sie, der Agent ruft das Ergebnis ab.
15
+
16
+ ## MVP-Status
17
+ - `server.py` MCP-Server (Tools: request_human_task, get_task_status)
18
+ - `store.py` SQLite-Queue (tasks.db)
19
+ - `fulfill.py` CLI fuer den Menschen (Tasks ansehen/erledigen)
20
+ - `demo.py` End-to-End-Demo (Agent -> Task -> Mensch -> Ergebnis)
21
+ - `test_smoke.py` Smoke-Test
22
+
23
+ ## Setup & Start
24
+ cd humanbottasks
25
+ unset PYTHONPATH
26
+ uv venv
27
+ uv pip install "mcp<2"
28
+ uv run server.py
29
+
30
+ ## Transporte
31
+ uv run server.py # stdio (Claude Desktop, Cursor, lokale Frameworks)
32
+ uv run server.py --transport streamable-http # HTTP-Endpoint http://127.0.0.1:8000/mcp (lokal/Remote-Agents)
33
+ uv run server.py --transport sse # Legacy-SSE http://127.0.0.1:8000/sse
34
+
35
+ Host/Port via Umgebungsvariablen: HBT_HOST (default 127.0.0.1), HBT_PORT (default 8000).
36
+ Fuer Remote-Zugriff: HBT_HOST=0.0.0.0 setzen.
37
+
38
+ ## Install (fuer andere Builder, 1 Zeile)
39
+ uvx --from git+https://github.com/humanbottasks/humanbottasks humanbottasks
40
+
41
+ ## Task-Typen
42
+ verification · physical_action · subjective_judgment · ground_truth_labeling · prove_human
43
+
44
+ ## MCP-Clients (installiert + konfiguriert)
45
+ - **Claude Desktop**: `C:\Users\marku\AppData\Roaming\Claude\claude_desktop_config.json`
46
+ - **Cursor**: `C:\Users\marku\.cursor\mcp.json`
47
+ - **Windsurf**: `C:\Users\marku\.codeium\windsurf\mcp_config.json`
48
+ - Templates in `config/` (falls neu einrichten noetig)
49
+
50
+ ## Naechste Schritte (Reihenfolge)
51
+ 1. Nachfrage-Test: Server laeuft, ein echter Agent ruft request_human_task.
52
+ 2. Website/Landing fuer Agent-Builder.
53
+ 3. Payments (Stripe/Circle) erst, wenn Nachfrage da ist.
@@ -0,0 +1,44 @@
1
+ # humanbottasks
2
+
3
+ Gemanagter Human-Service-Layer fuer AI-Agenten. Ein AI-Agent delegiert ueber MCP
4
+ eine Aufgabe, die er nicht selbst kann, an einen Menschen; der Mensch erledigt
5
+ sie, der Agent ruft das Ergebnis ab.
6
+
7
+ ## MVP-Status
8
+ - `server.py` MCP-Server (Tools: request_human_task, get_task_status)
9
+ - `store.py` SQLite-Queue (tasks.db)
10
+ - `fulfill.py` CLI fuer den Menschen (Tasks ansehen/erledigen)
11
+ - `demo.py` End-to-End-Demo (Agent -> Task -> Mensch -> Ergebnis)
12
+ - `test_smoke.py` Smoke-Test
13
+
14
+ ## Setup & Start
15
+ cd humanbottasks
16
+ unset PYTHONPATH
17
+ uv venv
18
+ uv pip install "mcp<2"
19
+ uv run server.py
20
+
21
+ ## Transporte
22
+ uv run server.py # stdio (Claude Desktop, Cursor, lokale Frameworks)
23
+ uv run server.py --transport streamable-http # HTTP-Endpoint http://127.0.0.1:8000/mcp (lokal/Remote-Agents)
24
+ uv run server.py --transport sse # Legacy-SSE http://127.0.0.1:8000/sse
25
+
26
+ Host/Port via Umgebungsvariablen: HBT_HOST (default 127.0.0.1), HBT_PORT (default 8000).
27
+ Fuer Remote-Zugriff: HBT_HOST=0.0.0.0 setzen.
28
+
29
+ ## Install (fuer andere Builder, 1 Zeile)
30
+ uvx --from git+https://github.com/humanbottasks/humanbottasks humanbottasks
31
+
32
+ ## Task-Typen
33
+ verification · physical_action · subjective_judgment · ground_truth_labeling · prove_human
34
+
35
+ ## MCP-Clients (installiert + konfiguriert)
36
+ - **Claude Desktop**: `C:\Users\marku\AppData\Roaming\Claude\claude_desktop_config.json`
37
+ - **Cursor**: `C:\Users\marku\.cursor\mcp.json`
38
+ - **Windsurf**: `C:\Users\marku\.codeium\windsurf\mcp_config.json`
39
+ - Templates in `config/` (falls neu einrichten noetig)
40
+
41
+ ## Naechste Schritte (Reihenfolge)
42
+ 1. Nachfrage-Test: Server laeuft, ein echter Agent ruft request_human_task.
43
+ 2. Website/Landing fuer Agent-Builder.
44
+ 3. Payments (Stripe/Circle) erst, wenn Nachfrage da ist.
@@ -0,0 +1,44 @@
1
+ # humanbottasks — Directory Submission Copy
2
+
3
+ Fertige Texte fuer MCP-Registries (mcp.so, PulseMCP, glama.ai/mcp, smithery.ai, Cline Marketplace).
4
+ Einfuegen bei Submission; Tagline/Description je nach Feld passend kuerzen.
5
+
6
+ ## Name
7
+ humanbottasks
8
+
9
+ ## Tagline (eine Zeile)
10
+ Human fallback for AI agents — delegate anything a model can't do to a real person, over MCP.
11
+
12
+ ## Description (lang)
13
+ humanbottasks is a managed human-service layer for AI agents. When an agent hits
14
+ something it can't or shouldn't do itself — verify a fact, make a phone call,
15
+ buy or ship something, judge whether text sounds natural, label ground-truth
16
+ data — it delegates the task to a human over MCP and polls for the result.
17
+
18
+ Two tools: `request_human_task` (submit a task with a type, description and max
19
+ price) and `get_task_status` (poll status and read the result).
20
+
21
+ Task types: verification, physical_action, subjective_judgment,
22
+ ground_truth_labeling, prove_human.
23
+
24
+ Transports: stdio (Claude Desktop, Cursor, Windsurf, local frameworks) and
25
+ streamable-http (remote agents).
26
+
27
+ ## Category / Tags
28
+ human-in-the-loop, task-delegation, human-fallback, agent-tools, mcp
29
+
30
+ ## Install
31
+ uvx --from git+https://github.com/humanbottasks/humanbottasks humanbottasks
32
+
33
+ ## MCP client config
34
+ {"mcpServers":{"humanbottasks":{"command":"uvx","args":["--from","git+https://github.com/humanbottasks/humanbottasks","humanbottasks"]}}}
35
+
36
+ ## Use cases (fuer Directory-Description)
37
+ - Prove a claim before the agent states it (verification)
38
+ - Phone calls, purchases, shipments (physical_action)
39
+ - "Does this sound natural / is this good?" (subjective_judgment)
40
+ - Ground-truth data for fine-tuning and evals (ground_truth_labeling)
41
+ - CAPTCHA / account / identity checks (prove_human)
42
+
43
+ ## Repo
44
+ https://github.com/humanbottasks/humanbottasks
@@ -0,0 +1,62 @@
1
+ """Task-Eingangs-Alarm: gibt NEUE offene Tasks aus; leere Ausgabe = nichts senden.
2
+
3
+ Wird als no_agent-Cron-Script genutzt: stdout wird verbatim an Telegram geliefert.
4
+ """
5
+ import os
6
+ import sqlite3
7
+
8
+ DB = "C:/Users/marku/humanbottasks/tasks.db"
9
+ STATE = "C:/Users/marku/humanbottasks/data/reported_ids.txt"
10
+
11
+
12
+ def _load():
13
+ if not os.path.exists(STATE):
14
+ return set()
15
+ with open(STATE, encoding="utf-8") as f:
16
+ return {ln.strip() for ln in f if ln.strip()}
17
+
18
+
19
+ def _save(ids):
20
+ os.makedirs(os.path.dirname(STATE), exist_ok=True)
21
+ with open(STATE, "w", encoding="utf-8") as f:
22
+ for i in sorted(ids):
23
+ f.write(i + "\n")
24
+
25
+
26
+ def main():
27
+ if not os.path.exists(DB):
28
+ return
29
+ conn = sqlite3.connect(DB)
30
+ conn.row_factory = sqlite3.Row
31
+ try:
32
+ rows = conn.execute(
33
+ "SELECT * FROM tasks WHERE status='pending' ORDER BY created_at"
34
+ ).fetchall()
35
+ except sqlite3.OperationalError:
36
+ return
37
+ finally:
38
+ conn.close()
39
+
40
+ if not rows:
41
+ return
42
+
43
+ reported = _load()
44
+ new = [r for r in rows if r["id"] not in reported]
45
+
46
+ # Zustand synchron halten (auch bereits bekannte pending merken)
47
+ _save([r["id"] for r in rows])
48
+
49
+ if not new:
50
+ return
51
+
52
+ lines = ["\U0001f195 Neue humanbottasks-Task(s):"]
53
+ for r in new:
54
+ lines.append(f" {r['id']} [{r['task_type']}] ${r['max_price_usd']:.2f}")
55
+ lines.append(f" {r['description']}")
56
+ lines.append("")
57
+ lines.append('Erledigen (im Ordner humanbottasks): python fulfill.py done <task_id> "<Ergebnis>"')
58
+ print("\n".join(lines))
59
+
60
+
61
+ if __name__ == "__main__":
62
+ main()
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "humanbottasks": {
4
+ "command": "C:\\Users\\marku\\humanbottasks\\.venv\\Scripts\\python.exe",
5
+ "args": ["C:\\Users\\marku\\humanbottasks\\server.py"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "humanbottasks": {
4
+ "command": "C:\\Users\\marku\\humanbottasks\\.venv\\Scripts\\python.exe",
5
+ "args": ["C:\\Users\\marku\\humanbottasks\\server.py"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1 @@
1
+ bad3938bf65a
@@ -0,0 +1,49 @@
1
+ """End-to-End-Demo: Agent delegiert Task -> Mensch erledigt -> Agent liest Ergebnis."""
2
+ import asyncio, sys, os, re
3
+ import store as q
4
+
5
+ from mcp import ClientSession, StdioServerParameters
6
+ from mcp.client.stdio import stdio_client
7
+
8
+ HERE = os.path.dirname(os.path.abspath(__file__))
9
+
10
+
11
+ async def main():
12
+ params = StdioServerParameters(command=sys.executable, args=["server.py"], cwd=HERE)
13
+ async with stdio_client(params) as (read, write):
14
+ async with ClientSession(read, write) as session:
15
+ await session.initialize()
16
+ tools = await session.list_tools()
17
+ print("== Tools ==")
18
+ for t in tools.tools:
19
+ print(" -", t.name)
20
+
21
+ print("\n== 1) Agent delegiert eine Task ==")
22
+ res = await session.call_tool(
23
+ "request_human_task",
24
+ {
25
+ "task_type": "subjective_judgment",
26
+ "description": "Bewerte, ob dieser Satz natuerlich klingt: 'Ich habe das Auto gewaschen.'",
27
+ "max_price_usd": 8.0,
28
+ },
29
+ )
30
+ text = res.content[0].text if res.content else str(res)
31
+ print(text)
32
+ m = re.search(r"task_id=([0-9a-f]+)", text)
33
+ tid = m.group(1) if m else None
34
+ assert tid, "keine task_id gefunden"
35
+
36
+ print("\n== 2) Status direkt nach Aufgeben ==")
37
+ res = await session.call_tool("get_task_status", {"task_id": tid})
38
+ print(res.content[0].text)
39
+
40
+ print("\n== 3) Mensch erledigt die Task ==")
41
+ q.complete(tid, "Der Satz klingt natuerlich und korrekt.")
42
+ print("Mensch hat abgeschlossen.")
43
+
44
+ print("\n== 4) Agent liest das Ergebnis ==")
45
+ res = await session.call_tool("get_task_status", {"task_id": tid})
46
+ print(res.content[0].text)
47
+
48
+
49
+ asyncio.run(main())
@@ -0,0 +1,17 @@
1
+ """CLI fuer den Menschen: offene Tasks ansehen und erledigen (MVP-Fulfillment)."""
2
+ import sys
3
+ import store as q
4
+
5
+ q.init()
6
+
7
+ if len(sys.argv) >= 4 and sys.argv[1] == "done":
8
+ q.complete(sys.argv[2], " ".join(sys.argv[3:]))
9
+ print("Erledigt:", sys.argv[2])
10
+
11
+ rows = q.pending()
12
+ if not rows:
13
+ print("Keine offenen Tasks.")
14
+ else:
15
+ for r in rows:
16
+ print(f"{r['id']} [{r['task_type']}] ${r['max_price_usd']:.2f} {r['description'][:90]}")
17
+ print("\nErledigen: python fulfill.py done <task_id> <Ergebnis-Text>")
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://glama.ai/mcp/schemas/server.json",
3
+ "maintainers": ["humanbottasks"]
4
+ }
@@ -0,0 +1,33 @@
1
+ """HTTP-Referenz: Agent verbindet sich ueber streamable-http (fuer Remote-/lokale Agents
2
+ auf anderen Maschinen). Vorher Server starten:
3
+
4
+ uv run server.py --transport streamable-http
5
+
6
+ Dann diesen Client laufen lassen (von ueberall im Netz, wenn HBT_HOST=0.0.0.0 gesetzt):
7
+ """
8
+ import asyncio
9
+ import sys
10
+
11
+ from mcp import ClientSession
12
+ from mcp.client.streamable_http import streamablehttp_client
13
+
14
+ URL = "http://127.0.0.1:8000/mcp"
15
+
16
+
17
+ async def main():
18
+ async with streamablehttp_client(URL) as (read, write, _):
19
+ async with ClientSession(read, write) as session:
20
+ await session.initialize()
21
+ tools = await session.list_tools()
22
+ print("Tools:", [t.name for t in tools.tools])
23
+ res = await session.call_tool(
24
+ "request_human_task",
25
+ {"task_type": "verification",
26
+ "description": "HTTP-Test: pruefe ob die Integration funktioniert",
27
+ "max_price_usd": 5.0},
28
+ )
29
+ print(res.content[0].text)
30
+
31
+
32
+ if __name__ == "__main__":
33
+ asyncio.run(main())
@@ -0,0 +1,90 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>humanbottasks — Human fallback for AI agents</title>
7
+ <meta name="description" content="Delegate anything your AI agent can't do — verification, physical actions, subjective judgment — to a real human over MCP.">
8
+ <style>
9
+ :root { --bg:#0a0a0f; --fg:#e8e8f0; --muted:#9a9ab0; --accent:#7c5cff; --accent2:#00d4aa; --card:#14141d; --border:#26263a; }
10
+ * { margin:0; padding:0; box-sizing:border-box; }
11
+ body { background:var(--bg); color:var(--fg); font-family:-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; line-height:1.6; }
12
+ a { color:var(--accent2); text-decoration:none; }
13
+ .wrap { max-width:960px; margin:0 auto; padding:0 24px; }
14
+ header { padding:32px 0; border-bottom:1px solid var(--border); }
15
+ .logo { font-weight:800; font-size:20px; letter-spacing:-0.5px; }
16
+ .logo span { color:var(--accent); }
17
+ .hero { padding:72px 0 48px; }
18
+ h1 { font-size:44px; line-height:1.15; letter-spacing:-1px; font-weight:800; }
19
+ h1 .grad { background:linear-gradient(90deg,var(--accent),var(--accent2)); -webkit-background-clip:text; background-clip:text; color:transparent; }
20
+ .sub { margin-top:20px; font-size:20px; color:var(--muted); max-width:640px; }
21
+ .cta { margin-top:32px; display:flex; gap:12px; flex-wrap:wrap; }
22
+ .btn { padding:12px 24px; border-radius:8px; font-weight:600; font-size:15px; display:inline-block; }
23
+ .btn-primary { background:var(--accent); color:#fff; }
24
+ .btn-ghost { border:1px solid var(--border); color:var(--fg); }
25
+ .grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:16px; padding:48px 0; }
26
+ .card { background:var(--card); border:1px solid var(--border); border-radius:12px; padding:24px; }
27
+ .card h3 { font-size:17px; margin-bottom:8px; }
28
+ .card p { color:var(--muted); font-size:15px; }
29
+ .code { background:var(--card); border:1px solid var(--border); border-radius:12px; padding:20px 24px; font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size:14px; overflow-x:auto; color:#c9d1ff; margin:24px 0; }
30
+ .code .c { color:var(--muted); }
31
+ .steps { padding:32px 0; counter-reset:step; }
32
+ .step { display:flex; gap:16px; align-items:flex-start; margin-bottom:24px; }
33
+ .step .n { background:var(--accent); color:#fff; border-radius:50%; width:32px; height:32px; display:flex; align-items:center; justify-content:center; font-weight:700; flex-shrink:0; }
34
+ .step h4 { margin-bottom:4px; }
35
+ .step p { color:var(--muted); }
36
+ .chips { display:flex; flex-wrap:wrap; gap:8px; padding:24px 0 48px; }
37
+ .chip { border:1px solid var(--border); color:var(--muted); border-radius:999px; padding:6px 14px; font-size:13px; }
38
+ footer { border-top:1px solid var(--border); padding:32px 0; color:var(--muted); font-size:14px; }
39
+ .h2 { font-size:28px; letter-spacing:-0.5px; font-weight:700; margin-top:8px; }
40
+ </style>
41
+ </head>
42
+ <body>
43
+ <header><div class="wrap"><div class="logo">human<span>bot</span>tasks</div></div></header>
44
+
45
+ <section class="hero"><div class="wrap">
46
+ <h1>Your agent can't do everything.<br><span class="grad">Now it can ask a human.</span></h1>
47
+ <p class="sub">humanbottasks is a managed human-service layer for AI agents. Delegate verification, physical actions and subjective judgment to a real person — over MCP, one line.</p>
48
+ <div class="cta">
49
+ <a class="btn btn-primary" href="https://github.com/humanbottasks/humanbottasks">Get started</a>
50
+ <a class="btn btn-ghost" href="#install">View install</a>
51
+ </div>
52
+ </div></section>
53
+
54
+ <section class="wrap">
55
+ <div class="grid">
56
+ <div class="card"><h3>Delegate anything</h3><p>Verification, phone calls, purchases, data labeling, subjective judgment — whatever the model can't or shouldn't do itself.</p></div>
57
+ <div class="card"><h3>Standard MCP</h3><p>Works with Claude Desktop, Cursor, Windsurf and any local agent framework. stdio for local, HTTP for remote.</p></div>
58
+ <div class="card"><h3>You stay in control</h3><p>A real human fulfills the task; your agent polls the result. You set the max price per task.</p></div>
59
+ </div>
60
+ </section>
61
+
62
+ <section class="wrap" id="install">
63
+ <div class="h2">Install</div>
64
+ <div class="code"><span class="c"># one command</span><br>uvx --from git+https://github.com/humanbottasks/humanbottasks humanbottasks</div>
65
+ <div class="code"><span class="c"># MCP client config (Claude Desktop / Cursor / Windsurf)</span><br>{"mcpServers":{"humanbottasks":{"command":"uvx","args":["--from","git+https://github.com/humanbottasks/humanbottasks","humanbottasks"]}}}</div>
66
+ </section>
67
+
68
+ <section class="wrap">
69
+ <div class="h2">How it works</div>
70
+ <div class="steps">
71
+ <div class="step"><div class="n">1</div><div><h4>Agent delegates</h4><p>The agent calls request_human_task with a description and max price.</p></div></div>
72
+ <div class="step"><div class="n">2</div><div><h4>Human fulfills</h4><p>A real person does the task and submits the result.</p></div></div>
73
+ <div class="step"><div class="n">3</div><div><h4>Agent reads the result</h4><p>The agent polls get_task_status and continues with the answer.</p></div></div>
74
+ </div>
75
+ </section>
76
+
77
+ <section class="wrap">
78
+ <div class="h2">Task types</div>
79
+ <div class="chips">
80
+ <span class="chip">verification</span>
81
+ <span class="chip">physical_action</span>
82
+ <span class="chip">subjective_judgment</span>
83
+ <span class="chip">ground_truth_labeling</span>
84
+ <span class="chip">prove_human</span>
85
+ </div>
86
+ </section>
87
+
88
+ <footer><div class="wrap">humanbottasks — human fallback for AI agents. © 2026</div></footer>
89
+ </body>
90
+ </html>
@@ -0,0 +1,18 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "humanbottasks"
7
+ version = "0.1.0"
8
+ description = "Human fallback for AI agents: delegate tasks a model can't do to a human, over MCP."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = ["mcp<2"]
12
+
13
+ [project.scripts]
14
+ humanbottasks = "server:main"
15
+
16
+ [tool.hatch.build.targets.wheel]
17
+ packages = []
18
+ force-include = { "server.py" = "server.py", "store.py" = "store.py", "fulfill.py" = "fulfill.py", "alarm.py" = "alarm.py" }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.humanbottasks/humanbottasks",
4
+ "title": "humanbottasks",
5
+ "description": "Human fallback for AI agents: delegate tasks to a human over MCP.",
6
+ "websiteUrl": "https://humanbottasks.github.io/humanbottasks/",
7
+ "repository": {
8
+ "url": "https://github.com/humanbottasks/humanbottasks",
9
+ "source": "github"
10
+ },
11
+ "version": "0.1.0",
12
+ "packages": [
13
+ {
14
+ "registryType": "pypi",
15
+ "registryBaseUrl": "https://pypi.org",
16
+ "identifier": "humanbottasks",
17
+ "version": "0.1.0",
18
+ "transport": {
19
+ "type": "stdio"
20
+ }
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,83 @@
1
+ """humanbottasks MCP-Server: AI-Agenten delegieren Tasks an Menschen.
2
+
3
+ Der Server exponiert zwei Tools ueber MCP:
4
+ - request_human_task: Agent stellt eine Aufgabe ein
5
+ - get_task_status: Agent fragt Status/Ergebnis ab
6
+
7
+ Transport (--transport): stdio (default), streamable-http, sse.
8
+
9
+ Ein Mensch erledigt die Tasks ueber fulfill.py (CLI).
10
+ """
11
+ import os
12
+ from mcp.server.fastmcp import FastMCP
13
+ import store as q
14
+
15
+ q.init()
16
+ mcp = FastMCP(
17
+ "humanbottasks",
18
+ host=os.environ.get("HBT_HOST", "127.0.0.1"),
19
+ port=int(os.environ.get("HBT_PORT", "8000")),
20
+ )
21
+
22
+ TASK_TYPES = [
23
+ "verification", # etwas pruefen/verifizieren
24
+ "physical_action", # physische Handlung (kaufen, verschicken, anrufen, unterschreiben)
25
+ "subjective_judgment", # subjektives Urteil (klingt natuerlich? ist gut?)
26
+ "ground_truth_labeling", # Daten labeln / Ground-Truth erzeugen
27
+ "prove_human", # CAPTCHA / Identitaets-/Konto-Verifikation
28
+ ]
29
+
30
+
31
+ @mcp.tool()
32
+ def request_human_task(task_type: str, description: str, max_price_usd: float = 10.0) -> str:
33
+ """Delegiere eine Aufgabe an einen menschlichen Arbeiter.
34
+
35
+ Nutze das fuer alles, was du als KI nicht selbst erledigen kannst:
36
+ physische Aktionen, Verifikation, subjektive Urteile oder Ground-Truth-Labeling.
37
+
38
+ Args:
39
+ task_type: Eine von 'verification', 'physical_action', 'subjective_judgment',
40
+ 'ground_truth_labeling', 'prove_human'.
41
+ description: Klare, konkrete Beschreibung der Aufgabe.
42
+ max_price_usd: Maximalpreis in USD, den du bereit bist zu zahlen.
43
+
44
+ Returns:
45
+ Eine task_id, mit der du den Status abfragen kannst.
46
+ """
47
+ if task_type not in TASK_TYPES:
48
+ return f"Fehler: task_type muss eine von {TASK_TYPES} sein, nicht '{task_type}'."
49
+ if not description.strip():
50
+ return "Fehler: description darf nicht leer sein."
51
+ tid = q.add_task(task_type, description.strip(), max_price_usd)
52
+ return f"Task angenommen. task_id={tid}. Status: get_task_status('{tid}')."
53
+
54
+
55
+ @mcp.tool()
56
+ def get_task_status(task_id: str) -> str:
57
+ """Status und Ergebnis einer delegierten Task abfragen.
58
+
59
+ Args:
60
+ task_id: Die task_id aus request_human_task.
61
+
62
+ Returns:
63
+ 'pending'/'done' plus Ergebnis, wenn fertig.
64
+ """
65
+ t = q.get_task(task_id)
66
+ if not t:
67
+ return f"Unbekannte task_id: {task_id}"
68
+ if t["status"] == "done":
69
+ return f"Fertig. Ergebnis: {t['result']}"
70
+ return f"Status: {t['status']} (Typ: {t['task_type']}, max ${t['max_price_usd']:.2f})"
71
+
72
+
73
+ def main():
74
+ import argparse
75
+ p = argparse.ArgumentParser(description="humanbottasks MCP-Server")
76
+ p.add_argument("--transport", default="stdio",
77
+ choices=["stdio", "sse", "streamable-http"])
78
+ a = p.parse_args()
79
+ mcp.run(transport=a.transport)
80
+
81
+
82
+ if __name__ == "__main__":
83
+ main()
@@ -0,0 +1,52 @@
1
+ """SQLite-Task-Queue fuer humanbottasks (minimales MVP)."""
2
+ import sqlite3, uuid, time, os
3
+
4
+ DB = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tasks.db")
5
+
6
+
7
+ def _conn():
8
+ c = sqlite3.connect(DB)
9
+ c.row_factory = sqlite3.Row
10
+ return c
11
+
12
+
13
+ def init():
14
+ with _conn() as c:
15
+ c.execute("""CREATE TABLE IF NOT EXISTS tasks (
16
+ id TEXT PRIMARY KEY,
17
+ task_type TEXT NOT NULL,
18
+ description TEXT NOT NULL,
19
+ max_price_usd REAL NOT NULL,
20
+ status TEXT NOT NULL DEFAULT 'pending',
21
+ result TEXT,
22
+ created_at REAL NOT NULL,
23
+ completed_at REAL
24
+ )""")
25
+
26
+
27
+ def add_task(task_type, description, max_price_usd):
28
+ tid = uuid.uuid4().hex[:12]
29
+ with _conn() as c:
30
+ c.execute(
31
+ "INSERT INTO tasks (id, task_type, description, max_price_usd, status, created_at) VALUES (?,?,?,?,?,?)",
32
+ (tid, task_type, description, max_price_usd, "pending", time.time()),
33
+ )
34
+ return tid
35
+
36
+
37
+ def get_task(tid):
38
+ with _conn() as c:
39
+ return c.execute("SELECT * FROM tasks WHERE id=?", (tid,)).fetchone()
40
+
41
+
42
+ def pending():
43
+ with _conn() as c:
44
+ return c.execute("SELECT * FROM tasks WHERE status='pending' ORDER BY created_at").fetchall()
45
+
46
+
47
+ def complete(tid, result):
48
+ with _conn() as c:
49
+ c.execute(
50
+ "UPDATE tasks SET status='done', result=?, completed_at=? WHERE id=?",
51
+ (result, time.time(), tid),
52
+ )
@@ -0,0 +1,35 @@
1
+ """Smoke-Test: Queue end-to-end + MCP-Handshake (Tools auflisten + Task aufgeben)."""
2
+ import asyncio, sys, os
3
+ import store as q
4
+
5
+ # 1) Queue end-to-end
6
+ q.init()
7
+ tid = q.add_task("verification", "Testtask", 5.0)
8
+ q.complete(tid, "OK")
9
+ t = q.get_task(tid)
10
+ assert t["status"] == "done" and t["result"] == "OK", "queue flow broken"
11
+ print("queue OK:", tid)
12
+
13
+ # 2) MCP-Handshake + Tool-Aufruf
14
+ from mcp import ClientSession, StdioServerParameters
15
+ from mcp.client.stdio import stdio_client
16
+
17
+ HERE = os.path.dirname(os.path.abspath(__file__))
18
+
19
+
20
+ async def main():
21
+ params = StdioServerParameters(command=sys.executable, args=["server.py"], cwd=HERE)
22
+ async with stdio_client(params) as (read, write):
23
+ async with ClientSession(read, write) as session:
24
+ await session.initialize()
25
+ tools = await session.list_tools()
26
+ print("tools:", [t.name for t in tools.tools])
27
+ res = await session.call_tool(
28
+ "request_human_task",
29
+ {"task_type": "verification", "description": "Smoke-Test", "max_price_usd": 1.0},
30
+ )
31
+ text = res.content[0].text if res.content else str(res)
32
+ print("call result:", text)
33
+
34
+
35
+ asyncio.run(main())