A marketplace where the unit of sale is a single GitHub issue.
A company or an open source maintainer attaches a fixed price to an issue. An AI agent reads the issue and the repository, then suggests an effort estimate, a range and a written justification. The suggestion is advice: the publisher names the price, and the only thing that refuses one is the $5 to $100,000 bound. A contributor claims the issue and opens a pull request. An agent reviews the submission against the acceptance criteria and the project's own checks. Payment settles in USDC on Arc once the work is accepted.
Open source is infrastructure that mostly goes unfunded. The issues that sit unresolved for years are rarely the hardest ones; nobody has money attached to them. Companies that ship open source components have a budget, and increasingly a legal obligation, but no way to direct either at a specific fix. Maintainers have a backlog and no budget.
Earlier bounty platforms proved the demand and then struggled to monetize it. Algora now sells recruiting on its homepage. IssueHunt moved to Japanese enterprise security programmes. Bountysource held developers' money, stopped paying, and filed for bankruptcy in November 2023. None of them made the buyer, the price or the settlement cheap enough for the transaction to become routine.
An enterprise or a maintainer picks an issue and attaches money to it. The pricing agent reads the issue and the surrounding code, then suggests an effort estimate, a range and its reasoning, as advice the publisher is free to ignore. The publisher types the price, and it is theirs to move while the issue is unfunded and unclaimed. The funds are committed to an escrow contract on Arc. The first contributor to claim the issue holds it exclusively, opens a pull request, and gets an automated review against the acceptance criteria and the repository's own checks. A human on the publisher's side makes the final acceptance call, and the contract releases payment.
Two decisions stay with a human: naming the price, and accepting the work. Scoping, pricing and first-pass review are agent work.
Nothing in the flow involves bidding. One price is set before publication and it is taken or left, which lets the publisher answer the budget question before committing money and lets the contributor know what the work pays before starting.
Settlement on Arc costs about a cent and finalizes in under half a second, and Circle's Gateway nanopayments go down to a millionth of a dollar. Paying a maintainer $20 was economically silly five years ago; it is not now.
The platform never holds customer funds. Committed money sits in the MisthosEscrow
contract on Arc and is released against an acceptance attestation, or refunded once the
deadline passes. The per-issue ceiling lives in the same contract, so a limit binds an
agent even if its key is compromised.
The regulatory deadline is real. The EU Cyber Resilience Act entered into force on 10 December 2024, with reporting obligations from 11 September 2026 and the main obligations from 11 December 2027. A private company that develops, commercialises or supports open source software is likely covered, which turns maintaining the open source you ship into a filing requirement with a budget attached.
Requires mise, which pins Node 22, Python 3.11, uv and Foundry.
mise install # install the toolchain
mise run setup # install every runtime's dependencies
mise run dev # API on :8000 and web app on :5173Open http://localhost:5173. The API reference is at http://127.0.0.1:8000/docs. To link your real GitHub account rather than a typed login, set up an OAuth App first: see Linking your real GitHub account locally.
To run the two servers in separate terminals:
mise run dev:api
mise run dev:webTests and linting (the browser test needs Chromium once: mise run setup:e2e, then
mise run test:e2e, which starts the API and the web app itself):
mise run test
mise run lint
mise run ci # exactly what CI runs on a pull requestEvery pull request runs the four suites in CI, one job per runtime — see .github/workflows/ci.yml.
Restore the seeded demo data at any point:
mise run resetState lives in memory by default and resets on every restart. To keep it, point the API at Postgres, or at a SQLite file for a single machine. The schema migrates itself on first use, and claim expiry, deadline refunds and the silent-publisher release run on their own:
MISTHOS_DATABASE_URL=postgresql://user:pass@localhost/misthos mise run dev:api
MISTHOS_DATABASE_URL=sqlite:///misthos.db mise run dev:apiWith a database configured, mise run reset and the dashboard's Reset button are
refused, because a reset deletes every row in it. Where the database is a demo you
mean to throw away, start the API with MISTHOS_ALLOW_DEMO_RESET=true as well.
To run more than one API process, add Redis as well. It holds the per-issue lock, the
Idempotency-Key answers and the rate-limit counters, which otherwise live in each
process:
MISTHOS_REDIS_URL=redis://localhost:6379/0 mise run dev:apiPublishing and claiming need a linked GitHub login. With nothing configured the Account page says linking is not set up here, and the simulation takes a login you type instead. To link your real account:
-
Create a GitHub OAuth App at https://github.com/settings/developers (OAuth Apps, New OAuth App).
-
Give it the homepage URL
http://localhost:5173and the authorization callback URLhttp://localhost:5173/api/v1/auth/github/callback. The API builds the callback fromMISTHOS_PUBLIC_URL, which defaults tohttp://localhost:5173, and Vite forwards/apito the API on :8000. -
Generate a client secret, and put the app's client ID and the secret in a
.envat the root of the repository, which mise loads into every task (backend/.envworks too: the API reads it frombackend/, where it runs):MISTHOS_GITHUB_OAUTH_CLIENT_ID=<the app's client ID> MISTHOS_GITHUB_OAUTH_CLIENT_SECRET=<the secret>
-
Restart
mise run dev, open http://localhost:5173 (not 127.0.0.1: GitHub returns to the address inMISTHOS_PUBLIC_URL, and your session lives on the one you opened), sign in, choose a side and press Link with GitHub.
GitHub is simulated until a GitHub App is configured. Register one from
backend/github-app-manifest.json (replace the webhook host first), install it on
the repository, and set its id, private key and webhook secret:
MISTHOS_GITHUB_APP_ID=123456 \
MISTHOS_GITHUB_APP_PRIVATE_KEY="$(cat misthos.private-key.pem)" \
MISTHOS_GITHUB_WEBHOOK_SECRET=... \
mise run dev:apiPublishing an issue with its number then reads it from GitHub and posts the engine's
suggestion. The publisher names the price with /misthos price 250; nothing can be
funded until they do. A pull request from the claimant that says Fixes #<n>
puts the issue in review, and merging it releases the payment.
Once the publisher who installed the App has signed in and linked that GitHub login, the repository runs the loop from GitHub alone:
- Label an issue
misthosto have it listed, with the engine's suggestion and no price. - Comment
/misthos price 250to name the price. - Comment
/misthos approveto fund it. - A contributor comments
/misthos claim, then opens the pull request. - The sweeper reviews it, and the merge pays.
docs/DEPLOY.md walks through it against a real repository.
Outside the simulation nothing is written anonymously. A wallet signs in with a
Sign-In with Ethereum message (POST /api/v1/auth/nonce, then /auth/verify), takes
a role once, publisher or contributor (/auth/role), and links its GitHub account
(/auth/github/start). A publisher acts only on its own issues, and a contributor
submits only a pull request it opened. The loop then runs through explicit actions:
| Who | Action | Endpoint |
|---|---|---|
| Publisher | Publish an issue and name its price | POST /issues |
| Publisher | Name a new price, while the issue is unfunded and unclaimed | PATCH /issues/{id}/price |
| Publisher | Approve the acceptance criteria, then the price they named, which commits the funds | POST /issues/{id}/criteria, then /fund |
| Contributor | Claim the issue, then submit the pull request | POST /issues/{id}/claim, then /submit |
| Either | Have the review agent judge it now rather than on the sweeper's next pass | POST /issues/{id}/review |
| Publisher | Merge on GitHub, which releases the payment | The webhook |
Linking needs a GitHub OAuth App (MISTHOS_GITHUB_OAUTH_CLIENT_ID and
MISTHOS_GITHUB_OAUTH_CLIENT_SECRET, see
Linking your real GitHub account locally);
without one the simulation links a typed login and a deployment links none. Set
MISTHOS_SESSION_SECRET to keep sessions across a restart. The demo stepper
(/advance and /complete) runs only in the simulation, because it fabricates the
pull request and the merge.
The web app does all of this from Account and each issue's page, which shows each party only the step that is theirs. In the simulation there is no need for a wallet extension: the demo publisher and contributor wallets are throwaway keys kept in the browser, and GitHub is simulated, so the contributor opens their pull request and the publisher merges it with a button. Use two browsers, or a private window, to be both sides at once.
The engine's suggestion moves toward what similar work settled at on the platform, and its
confidence is only as high as that history allows. It is advice: the publisher names the
price, and the only thing that refuses one is the $5 to $100,000 bound. A publisher's own
books are still read for display rather than to cap a price: the operator connects Firefly
III, or a beancount ledger with a Fava budget, in MISTHOS_FINANCE_CONNECTIONS (see
backend/.env.example), and the publisher sees what is left. To check the weights
against issues whose worth is known:
mise run pricing:calibrate # the corpus of real, scored issues--settled replays the platform's own settlements instead. It is not a check against
known worth: a settled amount is what a publisher paid rather than an independent
valuation, so it measures self-consistency (how far today's engine has moved from the one
that priced those issues), and it fits nothing.
cd backend && uv run python -m misthos.services.calibration --settledPlans in the web app lists Open, Team and Enterprise as 06 prices them. A
publisher buys Team there without a conversation by sending 249 USDC on Arc from its
wallet; the API reads the transfer from the chain before switching the plan on. Set
MISTHOS_PLATFORM_WALLET to the platform's wallet so payments have somewhere to go.
In the simulation, a button pays on a simulated rail. Enterprise is agreed with us and
recorded by an operator with python -m misthos.services.contracts.
To run the web app, the API, the worker and the edge against Postgres and Redis, the way it ships:
docker compose up --builddocs/DEPLOY.md covers what each service is, the logs and metrics, and deploying the escrow to Arc testnet.
Every submitted commit is reviewed against the issue's acceptance criteria without
anyone asking. Set MISTHOS_ANTHROPIC_API_KEY and a model reads the diff; without
it, a rule reviewer judges only what the file list proves. The key is spent at
MISTHOS_ANTHROPIC_API_URL, an Anthropic-compatible endpoint that is DeepSeek's by
default. To see how well the reviewer agrees with the hand-labelled regression
corpus, by complexity band:
mise run review:harnessMIT. See LICENSE.