HireLine
README.md
# HireLine
**An MCP and terminal workflow for agents to ask humans for help on Gibwork, with a separate approval vault.**
An agent can implement a checkout fix but cannot test it on a physical iPhone. HireLine lets it propose a small bounty, wait for evidence, check submissions against explicit criteria, and request payment approval. The agent-side client receives a `WalletSigner` adapter, not a wallet secret.
Built for the [Gibwork Developer Hackathon](https://gib.work/bounty/1052f22d-3f87-4b1d-b0d7-71a60679e7fa). This is a **non-web-app prototype**, using the real `@gibwork/sdk@0.2.0` from a CLI and an MCP server. It is not a production-audited wallet.
## Run the complete demo without an account or funds
Requires Node.js 22+ and npm (or pnpm). From this directory:
```sh
npm ci --ignore-scripts
npm test
node bin/hireline.js demo --yes
node bin/hireline.js demo --attack --yes
```
Alternative reproducible install: `pnpm install --frozen-lockfile --ignore-scripts`.
The happy path hires a fictional mobile tester, receives two fictional submissions, flags the suspicious one, requests a payout signature, and verifies the audit chain. The attack demo advertises a 5.125 USDC quote but includes an additional 500 USDC direct transfer; the vault refuses before approval.
**What is real:** Gibwork SDK calls, the `WalletSigner` interface, the HTTP vault, Ed25519 signatures, Solana versioned transaction bytes, and MCP stdio protocol. **What is simulated:** the Gibwork HTTP service, escrow program, network confirmation, workers, fees, and payouts. Nothing is broadcast on-chain. `--yes` is explicitly a non-human demo approval, not evidence of human authorization.
Run `node bin/hireline.js demo` in an interactive terminal to type `approve` yourself. In a noninteractive shell the demo uses a visibly labelled test approver. Use a separate vault with terminal approval for live operations.
## Architecture
```text
Agent -> MCP or CLI -> Gibwork SDK -> prepared transaction
|
RemoteSigner (HTTP)
|
Vault process holding wallet key
decode -> policy -> owner -> sign
|
signed audit entry -> SDK submit
```
The vault checks direct SOL/token instructions it understands, token spending caps, supported instruction types and program allowlists. Unknown programs require first-use approval before pinning. **Pinned program instructions remain opaque and require approval on every call.** Caller-supplied action, title, quote and review are untrusted context, not proof of the transaction's effects. The approval card shows decoded transfers, program IDs and blockhash.
Funding and payout are different decisions: funding moves money into escrow; payout selects a worker. Both use prepare/sign/submit SDK methods. Submissions are data; deterministic checks offer a recommendation, never an independent guarantee of work quality. Pattern-based injection warnings are deliberately limited.
## What improved in this revision
- Audit verification is enforced before appending or computing spend; tampered history refuses further signatures. In-process truncation is detected.
- System account creation and conservative priority-fee estimates count against the SOL cap. Unsupported system/token instructions fail closed.
- Opaque program warnings prevent a caller from bypassing approval by labelling an escrow action differently.
- Concurrent signer requests keep separate approval context using `AsyncLocalStorage`.
- Auth messages require recognised operation/method/path combinations, unique fields, fresh timestamps and request hashes.
- Vault HTTP is loopback-only, bearer-authenticated and rejects malformed payloads. Live CLI auto-approval is disabled.
- Submission review traverses all reported pages, URL checks reject lookalike hosts, zero payout amounts and invalid polling parameters are rejected.
These are bounded prototype checks. See [SECURITY.md](SECURITY.md) for the trust boundary and remaining gaps.
## Tests and actual evidence
```sh
npm test # unit, HTTP, transaction attacks, end-to-end SDK, MCP stdio
npm run test:mcp # exercises all eight MCP tools through a real child process
npm run check:live # optional production READ ONLY request, no user wallet required
```
`check:live` generates an ephemeral wallet in a temporary directory, signs one public API authentication request through the vault, and fetches this hackathon's public listing. Transaction signing is disabled. [Recorded live result](docs/live-readonly-result.json) confirms API reachability; it does **not** prove funded mainnet execution.
See [verification results](docs/VALIDATION.md), actual [happy-path output](docs/sample-output.txt), [blocked-attack output](docs/sample-output-attack.txt) and the recording instructions in [DEMO_SCRIPT.md](docs/DEMO_SCRIPT.md).
## Live configuration (owner supervised)
Do not use a wallet containing material funds. Review the security document first. No live funding/payout was performed while preparing this entry.
### macOS / Linux
```sh
export HIRELINE_HOME="$PWD/.hireline-vault"
node bin/hireline.js init
# In the VAULT terminal only, using your own key file:
export HIRELINE_KEYPAIR_PATH=/absolute/path/to/dedicated-key.json
node bin/hireline.js vault --approver terminal
```
### Windows PowerShell
```powershell
$env:HIRELINE_HOME = Join-Path $PWD '.hireline-vault'
node bin/hireline.js init
# In the VAULT terminal only:
$env:HIRELINE_KEYPAIR_PATH = 'C:\absolute\path\dedicated-key.json'
node bin/hireline.js vault --approver terminal
```
In a second terminal, remove wallet secret variables. Supply `HIRELINE_VAULT_URL`, `HIRELINE_VAULT_TOKEN` and a **different agent state directory** via `HIRELINE_HOME`. Use your operating system's secret manager to pass the token; never commit it. The CLI default state directory contains both agent state and vault configuration for convenience; that default is not process isolation against a same-user agent.
Set `GIBWORK_PRODUCTION=1` explicitly for production; stage is the default. The wallet may need to be registered on Gibwork and funded for money-moving operations. Live supported transaction shapes may be refused by the conservative decoder; do not disable policy to force them through.
```sh
node bin/hireline.js doctor
node bin/hireline.js discover --n 3
node bin/hireline.js hire --title "Test checkout on iPhone" --instructions "Use our test environment and report reproduction steps" --why "Physical device required" --budget 5 --criterion "Device model and iOS version" --criterion "Screen recording"
node bin/hireline.js wait TASK_ID --timeout 60
node bin/hireline.js review TASK_ID
node bin/hireline.js pay TASK_ID SUBMISSION_ID --amount 5 --rating 5
node bin/hireline.js reject TASK_ID SUBMISSION_ID --reason "Evidence is missing"
node bin/hireline.js refund TASK_ID
node bin/hireline.js audit verify
```
Plain-language CLI criteria require human review. Machine-checkable criteria can be supplied through MCP; see [examples/job.json](examples/job.json). Rejecting a submission is an authenticated off-chain action and does not request a transaction signature.
If the SDK reports an ambiguous submission/network error, **do not re-create the bounty or retry payment blindly**. Inspect the task and transaction/intent status on Gibwork first. Automated reconciliation and idempotent recovery remain future work.
## MCP
Use [examples/mcp-config.json](examples/mcp-config.json) as a template and replace the absolute path and connection values. Do not pass wallet secrets into the MCP process. All eight tools are integration tested:
| Tool | Purpose |
|---|---|
| `hireline_hire_human` | Prepare, approve and submit a funded bounty |
| `hireline_wait_for_submissions` | Poll with a bounded timeout |
| `hireline_review_submissions` | Check declared acceptance criteria |
| `hireline_pay_submission` | Request owner approval for an escrow payout |
| `hireline_reject_submission` | Reject with actionable feedback |
| `hireline_refund_bounty` | Request approval to return escrow |
| `hireline_jobs` | Read local job state |
| `hireline_audit_verify` | Verify vault audit signatures and hash chain |
## Policy and optional phone experiment
Default policy allows USDC up to 25 per transaction and 50 per rolling 24 hours, counts signed direct token outflows conservatively even if the transaction is never broadcast, and asks for approval by default. Caps do not describe arbitrary inner-program effects. SOL rent through inner instructions is not fully decoded. Pin real program IDs independently; trust on first use is a convenience, not a program audit.
The existing Bland.ai phone adapter is retained as an **experimental optional feature**, not the primary security claim. `HIRELINE_PHONE_DRY_RUN=1` prints the payload and always refuses. Real calls require an API key, phone number and PIN, incur provider charges and disclose the approval request and spoken response to that provider. Phone integration has parser tests but no live-call validation in this delivery. Use the terminal for the primary demo.
## Submission package
[BOUNTY_SUBMISSION.md](docs/BOUNTY_SUBMISSION.md) contains the entry description and checklist. The [terminal replay video](docs/media/hireline-demo.mp4) and labelled PNG frames are included. The creator reports that the Hackathon role and two Discord sessions are already completed; the repository does not independently verify attendance.
MIT licensed. No user funds, secrets or personal phone numbers are included.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues