humanforai
Official# humanforai
Python client and command-line tool for [Human For AI](https://humanforai.dev) — a human endpoint for AI agents. Let your agent, pipeline, or script hire a **verified human operator** for tasks that need physical presence, human perception, or human judgment:
- **Real-world verification** — confirm a place, product, price, or claim exists, with photo/text evidence
- **Product or app testing** — a real human installs, uses, and reports
- **Human judgment and feedback** — tone, clarity, trustworthiness, design quality
- **AI output review** — human review before your output reaches production
- **Data collection** — gathering or labeling that needs human perception or local access
- **Local physical-world tasks** — visit, photograph, check, measure, observe
- **Decision escalation** — a human read on a judgment call before you act
- …and anything else a human can legally and safely do (`custom_human_in_the_loop`)
**No API key. Free during the proof-of-concept pilot.** Every task is reviewed by the human before acceptance; illegal, harmful, deceptive, unsafe, or privacy-invasive tasks are rejected. First response within 12 hours, any day of the week — typically much faster.
Zero dependencies (standard library only). Python 3.9+.
## Install
```bash
pip install humanforai
```
With offline receipt verification (needs `cryptography`):
```bash
pip install "humanforai[receipt]"
```
## Command line
```bash
humanforai services # the catalog with task_type identifiers
humanforai submit \
--type real_world_verification \
--description "Verify that [business] at [address] is open; photograph the storefront and posted hours." \
--location "City, address or area" \
--output-format text_report_with_photos \
--email you@your-domain.com
humanforai status HFAI-2026-XXXXXXXXXXXXXXXX # one look
humanforai status HFAI-2026-XXXXXXXXXXXXXXXX --watch # poll until delivered or rejected
humanforai message --reply-to you@your-domain.com --message "Can you cover [city] next week?"
humanforai thread MSG-ID --token ACCESS_TOKEN
humanforai verify-receipt HFAI-2026-XXXXXXXXXXXXXXXX # offline check of the signed receipt
humanforai health
```
Every command accepts `--json` for raw output. Exit codes: `0` ok, `2` usage, `3` API error, `4` the task was rejected.
No mailbox? Autonomous agents can submit with `--status-poll` instead of `--email`: the deliverable arrives as text in `operator_notes` on the status endpoint (budget: one such task per client per day). Keep the `task_id` — it is your only key to the result.
## Python
```python
from humanforai import Client, HumanForAIError
client = Client(requester="my-agent/1.0")
task = client.submit_task(
task_type="ai_output_review",
description="Review these 10 AI-written product descriptions for plausibility and tone; "
"verdict + one-line reason each: [content or link].",
output_format="structured_json",
contact_email="you@your-domain.com",
)
print(task["task_id"], task["status_url"])
# Human review is not instant. Poll every minute or slower.
final = client.wait_for_task(task["task_id"], poll_interval=120)
print(final["status"], final.get("operator_notes"))
```
Errors are structured:
```python
try:
client.get_task("HFAI-NOPE")
except HumanForAIError as exc:
print(exc.status, exc.error, exc.message, exc.details, exc.rate_limit)
```
Every response carries the standard `RateLimit-*` headers; the most recent set is on `client.last_rate_limit`. Retrying a submission with the same `idempotency_key` replays the original response instead of creating a duplicate.
### Status transparency
`get_task` returns progress, not just the final state: `seen_by_operator_at` (the moment a human actually saw the task), `eta` (set on acceptance), and `status_history` (`submitted → accepted → delivered`, or `rejected`).
### Signed receipts
Every delivered task carries `receipt`, a compact JWS (Ed25519) binding the deliverable's SHA-256 to the task's lifecycle timestamps. Verify it offline against the public key at `https://humanforai.dev/.well-known/jwks.json`:
```python
from humanforai.receipt import verify_receipt
task = client.get_task(task_id)
payload = verify_receipt(task["receipt"], client.jwks(), deliverable_text=task["operator_notes"])
```
A valid receipt proves the deliverable is byte-identical to what was delivered and that it was issued by humanforai.dev. It does not prove the timestamps were witnessed by anyone else — they are the service's own signed assertion. Details: <https://humanforai.dev/trust#receipts>.
## Other ways in
- **MCP** (streamable HTTP, no auth): `https://humanforai.dev/mcp` — or `npx -y humanforai` for stdio clients
- **REST**: <https://humanforai.dev/api> · OpenAPI: <https://humanforai.dev/openapi.json>
- **Agent manifest**: <https://humanforai.dev/.well-known/agent.json> · **llms.txt**: <https://humanforai.dev/llms.txt>
- **Agent skill in one fetch**: <https://humanforai.dev/skill.md>
## Trust, in one paragraph
You never pay, never create an account, and are never asked for credentials — a request for payment or credentials is not from this service. You send a task description and an optional contact email; the worst case is a rejected task. Deliverables are one careful human's observation with stated confidence, not guaranteed truth. New here? Send a small, checkable test task first. Full analysis: <https://humanforai.dev/trust>.
## License
MIT
TDQS
Scored across 6 tools
Each tool targets a distinct resource and action: service discovery, task submission, task status polling, initiating a message thread, reading a thread, and replying within a thread. The descriptions clarify boundaries between tasks and messages, so an agent is unlikely to confuse them.
All tool names follow a consistent verb_noun pattern: get_human_services, submit_human_task, check_task_status, message_human_operator, check_message_thread, reply_in_message_thread. The verbs are clear and the objects are descriptive, with no style mixing.
Six tools is well-scoped for a human-in-the-loop service: two for task lifecycle (submit/check), three for threaded messaging (message/check/reply), and one for capability discovery. Every tool serves a distinct purpose without bloat.
The core workflows are covered: discover services, submit tasks, track task status, and hold asynchronous conversations. Minor gaps exist such as no explicit task cancellation or listing all tasks, but these can be worked around via messaging and the returned task_id, so the surface is largely complete for the stated purpose.