skip to content

Post a bounty

You have work you want done and money to pay for it. A posting turns that into something a developer can find, claim, and finish — without you handing over repository access to a stranger first.

This is the other half of claims. That page is written for the developer doing the work; this one is for the person paying.

Who can post

Posting is by invitation while we pilot it. The capability is tied to your GitHub account, so there is no separate login and no company profile to fill in.

Sign in on the web at /dashboard and open the postings tab. If the tab is not there, your account does not have the capability yet.

A terminal session cannot post, even a linked one. A CLI session lasts thirty days, and that is too long a key to leave lying around for something that spends money.

Writing the posting

Six fields carry the weight:

Field What it is for
Title One line, at most 140 characters.
Spec What a developer actually works from. Worth ten minutes.
Price Whole dollars.
Repo owner/repo. Mark it private if it is.
Stack tags Up to 12. They decide who sees this.
Claim mode Open, or approval-only.

Optional: a link to an existing issue, an effort estimate in your own words, and a note about whether you welcome AI-assisted work.

Tags are how developers find you. Matching runs on tag overlap, so a posting tagged rust and postgres reaches people who work in those; an untagged one reaches nobody in particular. Write them the way you would write them on a job post.

The spec is the deliverable. A developer decides whether to claim by reading it, and then works from it. A one-line spec produces one-line work, and the price you set does not fix that.

Drafting from an AI assistant

You do not have to start in the browser. Point any MCP client — Claude Desktop, Claude Code, Cursor — at https://terminalhire.com/api/founder/mcp and your assistant can draft a posting from whatever it already knows about the problem. Nothing to install.

What it can do is draft. draft_posting writes a draft and hands back a link; you open the link, sign in, read the posting rendered, and confirm it. Until you do, no developer can see it and nothing is published. The link grants nothing on its own — opening it signed out asks you to sign in, and drafts expire after a day.

Two other tools read your own postings back to you: a list, and a count of how many are waiting on a decision from you. Both need your session token in the connector's Authorization header. Neither of them, and no other tool on that server, can accept, reject, or withdraw anything — those are decisions you make signed in, on the web.

A posting you confirm this way is recorded as agent-drafted and human-confirmed. It is your posting; the record just says how it was written.

Open or approval-only

An open posting can be claimed by anyone. Good for a public repo where a pull request is the whole interaction.

An approval-only posting shows up in the same places, but a developer registers interest and you decide. Nothing about your repo reaches them until you do.

If your repo is private, approval-only is forced — not as a default you can change, but on the server, whatever the form says. For a private repo, approving someone is granting them access, and that should never be something you did by leaving a checkbox alone.

What developers see before you approve

A posting on the public index carries an opaque handle like founder/b-9f2c4e6a8b0d, the price, the tags, the effort estimate, and the claim mode.

It does not carry your repository, your name, your GitHub login, or your email.

For a private repo it does not carry your title either. You wrote that title for yourself, not for publication, and a title like "Fix the auth bypass in the billing webhook" tells a stranger more than you meant to say. Private postings show a stand-in built from the tags — Private-repo bounty · rust, postgres — so a developer can still tell two of them apart.

Once you approve someone, they get the title and the spec. How much of the code they get is a separate choice, and it is yours — see the next section.

How much of a private repo you hand over

Approving a developer does not have to mean handing over the repo. You pick one of three levels when you write the posting, and a new posting starts at the tightest one.

Issue-only. The developer gets the repro, the stack trace, and the files the problem lives in. No access to the repository at all — we never mint a key for a posting at this level, so there is nothing to revoke later. Right for a bug you can describe precisely.

Sparse. The developer gets one directory or package, sent as a copy. We start from the files your issue text points at, then add whatever those files import, so the developer gets something that actually builds rather than a folder with holes in it. Right for work that lives in one corner of the codebase.

Full. The developer gets the repository. Right when the work is genuinely spread out, or when you already know who you are handing it to.

For issue-only and sparse, the screen shows you what is being left out as well as what is going: "42 files, 1,180 excluded." Read that number. A list of included files looks equally reasonable whether it is tight or far too generous, and the excluded count is the only part of the screen that tells you which one you are looking at.

If we find anything that looks like a secret in the files you supplied — a key, a token, a .env — we stop and send nothing. The refusal arrives while you are still scoping, before the posting exists, so a tripped scan never leaves you with a live posting that can't deliver code; the same scan runs again when you confirm, as the authoritative second check. Every file that arrives with content is scanned, even one outside the slice — if you sent its bytes, we looked at them. The same happens if the scan cannot finish: a scan that did not complete has not cleared anything, so we treat it as a refusal rather than a pass. You will see what tripped it and can narrow the slice or fix the file.

Connecting your GitHub App

Private-repo postings need the TerminalHire Founder GitHub App installed on the repo. You install it once, from the dashboard, and pick the repositories it can see — GitHub asks you, not us.

The App is how the code gets out and how the patch comes back. It reads contents and pull requests, and reads your Actions runs so we can show you whether the checks passed. It never holds a key of yours: access is a short-lived token we mint per posting and throw away.

Uninstall it whenever you like, from GitHub's settings. Postings that depended on it stop being able to deliver code, and say so on the row rather than failing quietly.

The work comes back as a patch

For a private repo the developer never pushes to your repository, and never holds a credential for it. They send a patch. We apply it on a branch in your repo, on your behalf, and only within the files you disclosed — a patch that reaches outside the slice is refused, and you see the refusal rather than a surprise commit.

Your own CI runs on that branch, because it is your repository and your workflows. When the run finishes, the result lands on the posting row: passed, failed, or still going. That is the evidence you decide on — your tests, not our claim about them.

Deciding

The postings tab sorts by what is waiting on you. A row marked needs you has a developer blocked on your answer, and the badge opens the panel that answers it.

When work arrives you accept or reject it, with a rating from 1 to 5 and an optional note.

For paid work, save a card first under Settings → Payments. Saving the card and publishing a posting do not charge it; a saved card is not escrow and does not guarantee a later charge will succeed. The final button says Accept & pay $X. That explicit click charges the posted amount. Only after Stripe confirms the charge does TerminalHire record the public acceptance and reserve the developer's payout.

The developer receives 90% of the posted amount. TerminalHire retains 10% and absorbs Stripe's processing fee. If the card is declined or needs authentication, no acceptance or payout is recorded; replace the card or retry from the same decision panel. Withdrawing before acceptance needs no refund because no charge exists.

An accept is public. A reject is not. An accepted decision becomes part of that developer's credential — the thing they can show someone else. A rejection is your private judgment of a person's work, and publishing it would turn claiming a bounty into a bet on a stranger's mood. Rejections stay between you and them.

Notes are redacted after 180 days. The decision and the rating stay.

How you hear about it

Four things get you an email: a developer claims your posting, a patch arrives, the checks finish, and the work is done and waiting on your verdict. Each email links straight to the row it is about — you sign in as normal, and the link grants nothing on its own.

We send to the public email on your GitHub profile. If your profile does not list one, you get no email — nothing else changes, and the postings tab is still exactly current whenever you open it.

Turning them off. Three ways, and only the last needs you to sign in:

  • Your mail client's own Unsubscribe button stops all four.
  • Every email carries two links: stop all these emails, and stop only this kind.
  • Settings → posting notifications in the dashboard, where each of the four is its own switch — and the only place you can turn them back on.

Most people want to keep "a dev claims your posting". That is the one where someone is waiting on you.

Turning email off never hides anything. The postings tab and the MCP count always show every event as it happens.

You can also read the same state without opening the dashboard: the founder MCP server's pending_count tool reports how many postings are waiting on you, and reports counts only. claim_progress goes one step further — how many attempts have been made on each posting and what your own checks said about the latest one.

Neither names the developer. That is a rule, not an oversight: the output of an MCP tool goes to whichever model your editor runs, and a developer working on your posting never agreed to that. Both tools are read-only, and there is no tool that sends a reply or records a decision — those happen on the dashboard, signed in.

Reading how the work went

Open a claim on the postings tab and you get the whole run of it: every attempt the developer made, the short commit for each one, what your checks said, and the notes you sent back, in order. Where you used to see only the latest attempt and a count of the rest, you now see what happened in each.

The developer sees the same sequence from their side, including the notes you write when you send feedback or reject something. Write them as if they will be read, because they will be.

Each attempt is also kept in your repository under refs/th/attempts/, so the code of an earlier try survives the next submission. These are not branches and not tags: they will not show up in your branch or tag lists, and they cannot trigger a workflow. They are there so the history stays inspectable.

Paying

Terminalhire records the decision. It does not move the money — you pay the developer directly, however you already pay people.

Taking a posting down

Withdraw removes a posting from the index. You will find it on the row in the postings tab, and it asks once before doing it.

You can withdraw a posting nobody has started. Once a developer has claimed it or opened a pull request against it, withdrawing is refused — somebody has already spent their evening on your problem, and deleting the posting out from under them is not an answer. Decide the open claim first: accept it, or reject it with a reason.

A withdrawn posting stops appearing to developers within a few minutes.

What you cannot do yet

Edit a posting. Changing the price or the spec after developers have read it is a fairness problem wearing the costume of a missing button, and we would rather leave the button missing than get the answer wrong. For now: withdraw and post again, which is honest about what happened.

Delete a posting. Withdraw hides it from developers; the record stays, because decisions attached to it are part of somebody's credential.

The gap that used to sit here — receiving a patch from a developer — is closed. A developer's claim is now registered against their verified GitHub identity, and a patch is accepted only from the person whose claim it is: they run terminalhire claim record, read the slice, and submit the patch from their terminal, and it lands on a branch in your repo with their commit authorship. On an approval-only posting nothing is delivered and no patch is accepted until you approve the claimant from the needs you panel.