v0.40.11 — 2026-07-29
The in-session founder posting release now includes the current claim lifecycle from main, so the npm package and Claude Code plugin ship one identical tree.
- Keeps the v0.40.10 local posting-draft and founder-surface behavior.
- Includes stalled-claim release and live CLI claim-approval sync from TERM-273/TERM-287.
- Rebuilds the committed plugin after the mainline integration so its source hash matches the package published to npm.
v0.40.10 — 2026-07-29
Founders can draft postings from an active coding session without giving an agent permission to publish or spend money.
terminalhire post draftcaptures a local, private, editable posting draft with branch, remote, changed-path, stack, command, output, and session-summary provenance. Drafting makes zero network calls.- Draft storage refuses symlinked state directories, secret-shaped content, home-directory paths, and incomplete capture. Files use the existing secret-state policy, atomic writes, and owner-only permissions.
post submitis a human-only, typed-confirmation handoff to the existing browser confirmation flow. The browser remains the only place that can publish, choose scope and price, connect GitHub, or attach payment policy.- Linked founders get a derived, overrideable founder lead in bare
jobsandbountiescommands. The statusline carries counts only; private posting titles, repositories, and claimant identities never enter it. - Developers can see whether a founder-authored spec was agent drafted and then explicitly confirmed by the founder.
v0.40.9 — 2026-07-28
Paid founder claims now complete the developer notification path at claim time, and review feedback points to a transition that can actually clear it.
- A successful paid founder claim stores a push-only token encrypted on the developer's machine, enables the existing score-free claim sync, and says how to revoke it. If that enrollment cannot finish, the claim remains recorded and the CLI prints the exact recovery command.
terminalhire claim status [<id>]now checks founder approvals on demand and joins claim ids to the local claim ledger. It still polls public PR state for open-source work.- With no stored token or during an approvals outage,
claim statusshows local state and an enrollment or retry hint instead of failing or erasing state. - A
reviseverdict now points to the existingclaim update <id> readytransition only after its blockers are fixed and review is rerun. - Marking that claim ready clears the stale revise verdict, so the next
claim submit <id>is accepted instead of repeating the same refusal. - The list guidance and submit refusal share one command, and tests exercise the claim's full lifecycle-plus-review state so the two surfaces cannot drift.
v0.40.8 — 2026-07-28
Founder bounty payments now say what actually happens.
- Saving a card, posting, claiming, approving, submitting, and rejecting work do not create a charge.
- Accept & pay charges the posted gross amount. Acceptance and payout are recorded only after Stripe confirms payment.
- The developer receives 90%; TerminalHire retains 10% and absorbs Stripe's processing fee.
- A saved card is not escrow or a guarantee that a later charge will succeed.
- Scraped and external open-source bounties keep their source platform's payment terms; TerminalHire takes no cut from them.
v0.40.7 — 2026-07-28
Nothing you can see changed. This closes the last version of the 0.40.5 consent bug — one that no code path could reach yet.
- The statusLine consent prompt now refuses anything that is not a typed yes. 0.40.6 fixed the bug by excluding the one bad value it had been shown. That left the next one open: a prompt returning nothing at all would still have installed, for the same reason Ctrl-D did. The check now asks what the answer is rather than listing what it must not be, so a prompt added later cannot bring the bug back in a new costume.
v0.40.6 — 2026-07-28
Fixes a consent bug shipped hours earlier in v0.40.5. Upgrade past 0.40.5.
- Ctrl-D at the statusLine prompt no longer counts as yes. Making the prompt default
to yes in 0.40.5 was written as "install unless the answer is
norno", and the prompt returns an empty answer when the input closes — so Ctrl-D, a closed terminal, or quittingterminalhire initpartway through all read as consent and wrote~/.claude/settings.json. So didnope,cancel, and any answer the two-letter test did not recognise. It now installs only ony,yes, or a bare Enter, and declines everything else. If 0.40.5 enabled a statusLine you did not ask for, remove it withterminalhire statusline --off— your previous statusLine is restored from the backup it made. - The update notice compares the right package. It read the first
package.jsonit found with a version field, which in the plugin layout could have been the plugin's rather than the CLI's.
v0.40.5 — 2026-07-28
The statusLine is on by default, tells you when an update is waiting, and one command stops repeating itself sixteen times.
- Connection notifications are on by default. The setup prompt used to demand the
literal word
yes— Enter declined,ydeclined — which made it the strictest step in onboarding, one below a prompt that sends a credential and accepts Enter. The reflex way to dismiss a prompt turned it off, so the surface carrying every notification was off for people who thought they had accepted it. It now reads[Y/n]with Enter meaning yes. The disclosure is still printed in full, an existing statusLine is still preserved and backed up, and anything that is noty,yesor a bare Enter declines — including Ctrl-D. A non-interactive stdin keeps the old bar: only the literal wordyesenables it there, so a pipe or a CI runner cannot turn it on by sending a newline. - An available CLI update shows in the statusLine. The plugin auto-updates; a globally
installed CLI does not, and the check that knew you were behind only ever said so in
refreshoutput. It now renders as⬆ terminalhire 0.40.4 → 0.40.5 — run: th update, last in the line, because people and payments outrank the tool. No new network call: the published version already rides in the index the CLI downloads. - A command no longer prints the same warning sixteen times. When the OS keychain is unavailable, the notice was emitted on every single read and write of the encrypted store, burying the output of whatever you ran. It is said once.
v0.40.4 — 2026-07-27
claim list now tells you what to type next.
- Every claim that can move shows the one command that moves it. The list printed a
state and an id and stopped there, which told you where a claim was and nothing about
how to advance it. A
Next:block under the accepted-PR rate now names the command per claim. A freshly claimed founder posting points atclaim slice, which is what hands you the work; an open-source claim points atclaim start, which forks and clones. Work in progress points atclaim submit, except fromin-review, where submit refuses — that one points atclaim update <id> readyfirst. A submitted claim points atclaim runs --watchfor founder work andclaim statusfor everything else. Merged and abandoned claims say nothing, because there is nothing to do.
v0.40.3 — 2026-07-27
Paid work waiting for you now announces itself, and it arrives sooner.
- A fresh install no longer marks every waiting bounty as already read. With no
badge history, the
💎 N paidcount treated the whole open board as seen and showed nothing. It was unrecoverable, too — the seen set only ever shrinks, so no later refresh could surface those postings. Install while paid work is open and you were simply never told. Missing history now means nothing has been seen, which is what it always meant. - An unchanged refresh stops re-downloading the index. The CLI now sends
If-None-Match, so a poll that learns nothing changed costs a header exchange instead of ~378KB. A stale validator can never strand you: if the server says "unchanged" about something the cache does not hold, the tick re-fetches in full. - The background refresh ticks every 2 minutes instead of every 10. Affordable
only because of the change above.
TERMINALHIRE_REFRESH_INTERVALstill overrides it, in seconds.
A posting now reaches your status line in up to 7 minutes rather than up to 15, and typically in 3–4. The remaining delay is the 5-minute edge cache on the index, not the refresh loop.
Why 0.40.3 and not 0.40.2. terminalhire@0.40.2 was already published to npm, from
a tree that contains none of the above — its tarball is byte-identical to 0.40.1 apart
from the version string in package.json. npm versions are immutable, so this ships as
0.40.3 rather than silently never reaching anyone. If you installed 0.40.2, you have
0.40.1's code under a different number; upgrade.
This is the second time in three releases (see 0.40.1 below). The lockstep guard checks that our seven files agree with each other and cannot see the registry at all, so a number burned outside the repo passes every check we run.
v0.40.1 — 2026-07-27
Fixes two defects in the v0.40.0 badges, both found on review before the release reached anyone through the plugin channel.
✅ N approvedno longer under-counts. Collecting the code slice for an open-mode claim used to clear one approval from the badge, even though open-mode claims are never counted in it — nothing needs approving. Only approval-only claims now acknowledge the badge.- A server outage no longer looks like "no approvals".
/api/claim/approvalsanswered a store failure with an empty list and a 200, which the CLI read as authoritative and used to discard which approvals it had already collected. Every approval then reappeared on the next successful refresh. The route now answers 503 when it cannot reach the store, and the CLI keeps its last known count.
Why 0.40.1 and not a re-publish of 0.40.0: terminalhire@0.40.0 was published to
npm ~33 minutes before the first of these fixes was written, so the tarball on the
registry does not contain them. npm does not allow republishing a version, and two
different artifacts must not share one version number. 0.40.0 remains on npm and is
superseded; the plugin channel never shipped it.
v0.40.0 — 2026-07-26
Two things a developer was never told: that a founder approved their claim, and that paid work had appeared.
Your statusline says when a founder said yes
Approve a developer's claim on a private posting and, until now, nothing reached
them. The approval notice was written for the founder's ladder, which excludes it
on the reasonable-sounding grounds that they already know — they clicked the
button. The developer, who is the one waiting, had to keep re-running
terminalhire claim slice <id> until the refusal turned into a slice.
The statusline now carries ✅ N approved, and it behaves like an obligation
rather than a notification: it does not fade after one tick, and looking at it
does not clear it. Fetching the slice does, because that is when you actually
have the work.
Needs terminalhire claim --push --keep-updated — checking on your behalf means
a request with your credential, which stays your decision. If you have not
enrolled and a claim is waiting on a founder, refresh now says so, reading only
your local claim file and sending nothing.
And when there is paid work you could take
💎 N paid joins it, for first-party postings a founder has put money behind.
It counts what is NEW since you last looked rather than what exists, so it goes
quiet on its own; terminalhire bounties is what marks it read, and only for the
rows that actually printed. Scraped bounty-board supply is deliberately not
included — nobody is waiting on you for those.
Notes
- Neither badge can carry a repo name, title or price. Both read a count, and the statusline has no path to the underlying list.
✅leads💎, which leads your messages: work granted to you by name outranks work anyone could take, which outranks a conversation.
v0.39.9 — 2026-07-26
The developer side of a founder posting opens: claim, slice, patch, runs.
A founder-posting claim is registered, not just noted
claim record on a founder posting now registers the claim server-side, bound to
your browser-verified GitHub identity — that registration is what a later paid
credential rests on. On an approval-only posting the claim waits in an
approval-pending state until the founder approves you; nothing is wrong and there
is nothing to retry. Contention stays real: an open posting can hold claims from
several developers, and registering does not lock anyone else out.
Read the slice, send the patch, read their CI — without ever holding the repo
Three verbs close the loop on a private repo you never clone:
claim slice <id>— the files the founder confirmed, contents included.claim submit <id>— on a founder posting this submits a patch over HTTP instead of opening a PR from a fork. The platform applies it to a branch in the founder's repo with your commit authorship; a patch touching a file outside the slice is refused. This call always asks for a fresh browser verification — it is the one action that writes to someone else's repository under your name, so the persistent background-push credential is never accepted for it.claim runs <id>— the founder's own CI verdict on your branch: passed, failed, or still running.
Founder bounties lead the ranked surfaces
A live, claimable founder bounty now pins above roles in bounties output and the
ambient tip rotation. Finished work no longer advertises: a posting whose work was
accepted leaves the supply instead of ranking forever, and an approval-only posting
already assigned to someone is listed but never pinned. A rejected claim frees the
bounty again.
v0.39.8 — 2026-07-26
profile --delete no longer leaves files behind that nothing can ever read.
It promised to remove "your local terminalhire profile and encryption key". It
removed the key, then left github-token.enc, chat-identity.enc,
repo-experience.enc and claim-push-token.enc sitting on disk, encrypted under
a key that no longer existed — and printed success.
- Every encrypted file is now deleted with the key. The old code swept a list
each store had to add itself to, and only one of the five ever did. The list is
gone;
--deletenow clears every.encfile in the terminalhire directory. - If you already have orphaned files, run
terminalhire profile --deleteagain. It works even when the key is already missing, so it clears what the older build left behind. No plaintext is touched — your config, saved claims, chat peers and session stay put. - A delete that cannot finish now stops instead of reporting success. If a file is locked (most likely on Windows, with another terminalhire running), the command exits with an error saying your key was not deleted, so nothing is orphaned. Close the other process and run it again.
v0.39.7 — 2026-07-26
A repo that welcomes AI with disclosure no longer scans as PROHIBITED.
Disclosure enforcement is not a ban (policy ruleset v3)
microsoft/TypeScript and microsoft/typescript-go both say they have no objection
to AI assistance — you just have to disclose it. The consequence sentence ("if you
do not include this disclosure, your PR will be closed") matched a prohibition
pattern, so the policy scan reported the exact opposite of the repo's actual
policy. The classifier now recognizes disclosure-enforcement sentences and reads
them as what they are: the teeth of a disclosure rule, verdict
disclosure-required. A genuine ban sharing a line with one still reads
prohibited. Ruleset v2 → v3, so previously stored policy acknowledgments
re-evaluate against the corrected verdict.
v0.39.6 — 2026-07-25
Founder-posted bounties reach you without --priced.
A founder posting is not scraped supply
Paid bounties sit behind --priced because scraped third-party paid listings used
to crowd roles out of the default view. A founder posting is different: it is
first-party, and someone is waiting to pay for that specific piece of work. Hiding
it behind a flag inverts the point, so bountySource === 'founder' is now exempt
from the demote. Scraped paid supply is unchanged.
Bounty lines also carry an effort estimate — small (~½ day), medium (~1 day),
large (multi-day) — and a bounty you have already claimed says so, pointing at
terminalhire claim status rather than offering to claim it again.
Why this is a separate release from v0.39.5
v0.39.5 was published minutes before the founder marketplace merged, so it does not contain these changes and npm versions cannot be rewritten. If you installed 0.39.5 you have every earlier fix; this release adds the founder supply path.
v0.39.5 — 2026-07-25
claim start tells you what it is doing.
Progress through fork, clone and branch
Claiming a large repository used to sit silent. On a repo the size of Firefox iOS that silence ran for minutes, which reads as a hang — there was no way to tell a working clone from a dead one. It now reports each phase as it goes:
✓ forking mozilla-mobile/firefox-ios → you/firefox-ios
✓ cloning you/firefox-ios receiving objects 62%
✓ cutting branch th/firefox-ios-4821
All three phases are covered, not just the clone. Forking is itself slow on a big repo, and the branch checkout has to write the whole worktree.
Progress goes to stderr, and only when both stderr and stdout are terminals. The
jobs and bounties skills and the MCP server read this CLI's stdout and cannot
tell decoration from data, so anything piping us gets output identical to before,
byte for byte. Redirect stdout to a file and you lose the progress line — the
cheaper mistake by a wide margin.
v0.39.4 — 2026-07-25
One change you can see, and it is a privacy one.
The spinner tip names the role, not the employer
A job tip used to read ↗ Senior Rust Engineer @ Stripe · 87% — …. It now reads
↗ Senior Rust Engineer · 87% — ….
That line is written into ~/.claude/settings.json, which Claude Code reads into
every session — on any repo, on any machine, including a work laptop. So it is
visible to anything that sees that file: a screen share, a screenshot, a support
bundle, a colleague glancing over, a dotfiles repo you sync. The role on its own
is ambient noise. The same line naming the employer says which company you are
looking at, and for anyone looking quietly that is the whole sensitivity.
The link is unchanged, so the tip still clicks through to the same place. Bounty and contribute tips still show their repository — an open-source repo is public work, not an employer you are quietly eyeing.
Under the hood the company is still read on your machine, to keep two same-titled roles at different employers from collapsing into one another in the rotation. It is simply never written out.
v0.39.3 — 2026-07-25
Three robustness fixes. Most of this you will never see; two bits you will.
A corrupt key no longer dumps a stack trace at you
If the shared encryption key on disk was damaged, terminalhire profile --show
printed a raw V8 stack trace and a Node.js v20 footer. It now prints the reason
in one line and stops. The exit code is still non-zero, so scripts and CI see the
failure exactly as before, and --verbose (or TERMINALHIRE_DEBUG=1) brings the
full trace back when you actually want it.
spinner --show tells you when a background refresh skipped
The refresh loop can decline to write — someone else holds the lock, the settings file changed underneath it, a symlink will not resolve. It used to decline in silence, so a spinner that quietly stopped updating looked like nothing at all was happening. The last refusal is now recorded and shown, per surface, with the real reason rather than a catch-all.
Windows: the job-status lock stops fighting itself
On Windows the lock could fail with EPERM and crash the command. Two causes: the
contended case was only recognised as EEXIST, and stale-lock recovery measured
staleness against the waiting process's own clock — so it deleted locks that a
healthy process was still holding, which on Windows leaves the file in a state
where every later open fails. The recovery was manufacturing the error. Recovery
now reads the lock file's own timestamp, and a lock that never frees is reported
rather than ignored.
v0.39.2 — 2026-07-25
Name the project you want to work on.
terminalhire contribute <owner/repo>
contribute used to rank whatever the shared index already held. Now it takes a
repo:
terminalhire contribute andrewyng/aisuite
That reads the repo's open, unassigned issues, ranks them against your local profile, and prints a claim command for each one.
If you have run terminalhire link, the read goes through terminalhire, which
scans the repo's AI-assistance policy and shows the verdict at the top — and a
repo whose CONTRIBUTING prohibits AI-assisted contributions gets no claim
command on any row. Unlinked, the repo is read directly on your own GitHub
token; there is no verdict to show yet, so the commands are printed and
claim record scans the policy itself before recording anything. Either way
the prohibition holds.
Bare terminalhire contribute behaves exactly as before.
Your profile does not leave the machine. Ranking is local, as always. The one new outbound call is a public read of the repo you named.
Naming a repo adds it to everyone's supply
When you are linked, a repo you name is submitted to the shared index, so the next person searching can find work there without knowing to ask for it. Submission changes what the crawler LOOKS at, never the bar it applies — a repo still has to clear the same quality gate to enter the shared pool, so a small project can be listed for you and never appear for anyone else. Submissions rotate round-robin and retire themselves after three crawls that surface nothing, so a few repos cannot crowd out the rest.
Looking up a repo without a linked session submits nothing.
v0.39.1 — 2026-07-25
A data-safety release. Two files the CLI writes to could be lost, and both failures were silent. Neither needed an attacker or an unusual setup.
The spinner will not overwrite a settings.json it cannot read
~/.claude/settings.json is not ours. Claude Code writes it, you hand-edit it,
and it holds your permissions, hooks, MCP servers, model and environment. The
spinner adds two keys to it, and used to do so by reading the file, editing
what it read, and renaming a fresh copy over the top.
If the read failed, the edit started from an empty object. So a settings.json caught mid-save — an editor part-way through writing it — parsed as nothing, and the next refresh replaced your whole configuration with a file containing only spinner verbs. No warning, no backup. The refresh runs every ten minutes.
The writer now tells "there is no file" apart from "there is a file and I cannot read it", and refuses to write on the second. Related fixes went with it:
- A symlinked settings.json is followed rather than replaced, so a dotfiles repo stays the live copy.
- The file keeps its own permissions and is flushed to disk before the rename.
It can be
0600and hold secrets; every spinner write used to widen it. - A permission you approve while the spinner is mid-write is far less likely to be clobbered by the older copy.
- A spinner block the CLI did not write is left alone instead of overwritten,
and a deliberate
spinnerTipsEnabled: falseis restored byspinner --offrather than deleted.
spinner --on, --off, and the --mode/--max/--frequency flags now say
when they skipped a write instead of reporting success either way.
One implementation of the chat key, so two processes cannot race it
crypto-store and github-auth each carried their own create-if-absent
sequence for ~/.terminalhire/key. One had been hardened into a no-replace
protocol; the other was still a plain check-then-write.
On a first run with no key yet, two processes could both see no key, both
generate one, and both write — last one wins. Anything already encrypted under
the loser's key became permanently unreadable, because that key then existed
nowhere. claim push runs in the background and races foreground commands on a
fresh install, so no unusual timing was required.
Key creation now lives in one place and both callers use it. A mangled key file also reports a clear error naming the file, instead of reading as empty and making every store look blank.
v0.39.0 — 2026-07-24
claim start speaks up when staying quiet would cost you the issue
Losing an issue you were already working on is usually not a technical failure. Someone else commented first, the maintainer assigned it to them, and your branch became dead work. Until now the CLI only spoke up when the repo's own docs asked it to — which left silent exactly the case where silence costs the most: a contested issue in a repo that states no process at all.
claim start now follows the same three-way rule the guide at
terminalhire.com/social-layer teaches:
- The repo states a process — follow it exactly, in their format. Unchanged.
- No stated process, but someone else is already circling — post one
substantive comment: your approach in a line, when a PR lands, and an explicit
invitation for the maintainer to redirect you before you sink a day. Give it
with
--intent "..."(plus an optional--eta "..."), or answer the prompt. - No stated process, nobody else on it — say nothing. Performing a ritual nobody asked for burns goodwill before you have written a line.
You always see the exact comment before it exists, and nothing is posted without your yes. If you have no approach to offer, nothing is posted at all — a bare "can I work on this?" is what gets ignored, not what wins the issue.
Releasing a staked claim offers to hand the issue back
If you staked an issue publicly and then release the claim, claim release now
offers to post a short stand-down. Without it, an issue you walked away from goes
on reading as taken to everyone who looks — including our own tooling, for a
fortnight.
It also will not quietly forget the stake. If nothing retracted it — you weren't
at a terminal, or the post failed — the claim is kept rather than deleted, so the
outstanding comment stays visible and retryable. --force releases anyway.
Also in this release
v0.38.0 was cut before a run of engine work landed, so the plugin and CLI pick all of it up here.
The AI-contribution policy scan got harder to fool. It decides whether we tell you a repo forbids AI-assisted contributions, so a miss is expensive in both directions — a false all-clear sends you into a repo that will reject the PR on sight, and a false alarm costs you a repo you were welcome in.
- A keyword scan alone reads the letters, not the meaning. A second, semantic read now runs behind it, so a policy stated in prose rather than in the words we happened to grep for is no longer invisible.
- An incomplete scan no longer resolves to a clean verdict. If we could not read everything, you are told that, rather than handed a "looks fine" that was never earned.
- A spent anonymous rate limit is reported as a rate limit, not as a policy finding. Running out of GitHub reads is not evidence about the repo.
Fixes elsewhere in the CLI. First-run chat no longer races itself into a
broken keystore; commands that hold secrets refuse a state directory that is a
symlink; chat reads piped input without racing its own budget; and the plugin
declares its own module type instead of inheriting one, which is what kept the
refresh monitor working on Windows.
v0.38.0 — 2026-07-23
The ambient statusline can finally reach every role that matches you
v0.37.0 fixed the order roles came back in. It did not fix their reach, and that turned out to be the real cause of "I keep seeing the same job postings".
Slot budgeting kept the top 12 roles as a stable head and then rotated a window of the next 60 — so rank 72 was a ceiling nothing could cross. Out of 260 matching roles, 188 were structurally unreachable, and always the same 188. Four earlier rounds tuned rotation clocks inside that frozen window, which is why each helped a little and the complaint survived.
The tail is now uncapped and ordered by how long it has been since you last saw a role, with never-surfaced roles first. Measured over 200 surfaces against the same pool: 72 → 260 roles reachable, deepest rank 71 → 259, coverage 58% → 96%. The head is unchanged — top-fit roles stay visible by design.
TH_SEEN_SELECT=0 restores the previous behaviour.
The MCP tools (jobs, contribute) read the same cached array, so they inherit
the wider reach for free.
Your seen-history no longer forgets while you are still looking
The store capped at 500 entries and the live store was sitting at exactly 500, so it had been quietly evicting for some time — and the selector cannot make a good decision about a role it has no memory of. Raised to 1500, and the probe now reports when the cap is reached instead of degrading invisibly.
A slow pipe into jpi is waited for, not truncated
The statusline hook read stdin under a flat 200 ms deadline measured from the first byte. A payload arriving in chunks — which is what a ~100 KB session blob through a 64 KB pipe does — could exhaust it mid-stream and render nothing.
The bound is now on inactivity, not total elapsed time: 200 ms while no data has arrived at all, 500 ms between chunks once a stream is in progress, and a 1.5 s hard ceiling. A stalled pipe still fails closed and fast; a slow-but-live writer is no longer cut off. Applies to both the POSIX and Windows readers.
v0.37.0 — 2026-07-22
Changed
terminalhire jobsno longer restarts at the top of the list every run. Roles you were shown recently sink and un-shown ones lead, so repeated runs work down your matches instead of replaying the same first page. Nothing is dropped — the count is still every role that matches you, just in a different order. Explicit paging (--page N,--all,--status) keeps the old fixed rank order so a page 2 still follows the page 1 you just read.- The
jobslist is also more varied within a single page, using the same diversification the ambient statusline already applied. Previously the two surfaces ordered the same matches differently without saying so. - The MCP tools (
jobs,bounties,contribute) stop returning the same list every call. They were re-sorting by match score and discarding the anti-repeat ordering the background refresh had already worked out, so an assistant asking twice in one session saw near-identical results. They now respect that ordering and cycle the lead every few minutes. Match scores are still reported on every result — they just no longer decide the sequence.
Added
terminalhire jobs --stable— opt out of the rotation and get the fixed, rank-ordered list when you want to look at exactly what you saw a minute ago.
Note
This release improves how listings are ordered on those surfaces. It does not change how many distinct roles the ambient statusline can reach, which is a separate limit still being worked on.
v0.36.1 — 2026-07-19
Changed
- Maintenance: internal cleanup + build hardening. Removed dead code paths in the CLI's local-encryption layer (no change to how your data is stored or read) and added a build guard so the shipped plugin can never include a platform-specific native binary. No user-facing behavior changes.
v0.36.0 — 2026-07-19
Added
- Reply to a connection without leaving your terminal. A new opt-in MCP chat server (
terminalhire mcp-chat) lets you reply to an accepted Terminalhire connection through a native prompt right inside Claude Code. Your message thread stays on your machine — only the reply you type is sent. It's a separate, opt-in server from the read-onlyterminalhire mcpsurface; enable it by adding it to your MCP host config.
Changed
- Sharper "winnable" signal on contribution opportunities. Contribution matches now detect when an issue already has a cross-referenced pull request — including PR attempts that never left a comment — so the opportunities you see are less likely to be already taken.
- More contribution opportunities surfaced. The contribution supply was widened, so a broader set of open-source issues can appear in your ambient surface.
v0.35.4 — 2026-07-18
Changed
- Contributions are on by default. Open-source contribution opportunities — where a merged pull request is verifiable proof of work for your résumé — now appear in your ambient surface without a separate opt-in. They ride the same anonymous index you already download for jobs, so nothing new leaves your machine; this only changes what's shown. If you'd previously turned contributions off (or never enabled them), they'll now show — and the surface mix presets (
config set mix jobs|balanced|credential, added in v0.35.3) finally control something visible. To opt out, set"contributeEnabled": falsein~/.terminalhire/config.json. - More varied lead cadence. Rotation clocks are de-phase-locked per install, so the roles surfaced in the spinner vary more between refreshes instead of advancing in lockstep.
Fixed
TERMINALHIRE_DIRis honored everywhere. If you point terminalhire at a custom state directory, every part of the CLI — config, cache, claims, and all other state — now respects it, instead of a few sites silently falling back to~/.terminalhire.
v0.35.3 — 2026-07-18
Added
- Surface mix presets — tune how much of the spinner is jobs vs. contributions. Run
terminalhire config set mix jobs|balanced|credentialto bias the ambient surface toward paid roles, an even split, or credential-building open-source contributions. The default now leans further toward contributions (balanced), andTH_MIXlets you override the preset per session without changing your saved config.
Changed
- Shorter, cleaner job links.
/j/job URLs now use compact 8-character tokens, matching the/c/contribution links — a Work-With-Remote link's token drops from 100+ characters to 8. Every job link you've already shared keeps working; only newly generated links use the short form.
v0.35.2 — 2026-07-17
Changed
- The spinner's lead tip now rotates through your top-fit roles. Previously the most-visible first tip almost always showed the same #1 match; it now cycles over time across your top-tier roles, so the surface feels varied session to session while every lead stays a genuinely high-fit role. Set
TH_LEAD_ROTATE=0to restore the old always-best-first order.
v0.35.1 — 2026-07-17
Fixed
- macOS claim deep links now open your terminal. The
th:///terminalhire://claim-link handler previously delegated terminal-control to a detached background process that could not present the macOS Automation permission prompt, so a click could start and then do nothing. The handler now opens Terminal in the foreground of the link event (so macOS can grant the permission and attribute it to the Terminalhire handler), shows a notification with the exact recovery command if it still can't, and queues the claim soterminalhire claim/bounties/hubsurface it on your next run. Existing installs self-heal on the nextterminalhirecommand after updating, or runterminalhire protocol register.
v0.35.0 — 2026-07-17
terminalhire update(aliasupgrade) — stop remembering the npm command. Runningterminalhire updatenow checks your installed version against the latest published release (from your local index cache, no extra network call) and, if you're behind, auto-runsnpm install -g terminalhire@latestfor you — with a clear fallback message and the manual command if the install can't complete (e.g. permissions).--checkreports installed vs. latest without installing anything;--forcereinstalls even if you're already current. If you're running the Claude Code plugin's bundled copy,updatetells you it updates with the plugin instead of touching your global npm install.
v0.34.0 — 2026-07-17
- "Claim in terminal" links now work — run
terminalhire protocol registeronce. A newterminalhire protocol register/status/unregistercommand registers theth://URL scheme with your OS, so the Claim in terminal button on terminalhire.com opens the claim directly in your terminal instead of doing nothing. Registration is opt-in and one-time:initoffers it as an optional Step 7, and installs that skipinit(npm, homebrew, the plugin) never register it — so if that button has been silently failing for you, this release plus oneterminalhire protocol registeris the fix.protocol statustells you where you stand. The handler is local; a click passes only the claim token. terminalhire repo <owner/repo>— a private memory of your history in a repo. Newrepo,repo note, andrepo synccommands keep an encrypted, machine-local record of the repos you've worked in: how many PRs you've landed there, notes you write yourself, and a continuity signal built from your own merge history (repo syncbackfills it from GitHub — the one explicit, user-initiated network call). Nothing here is uploaded, shared, or comparative across users.bountiesandcontributenow favor repos you've already merged into. A repo you've landed work in gets a small local score boost and an inline note (↑ you've merged here twice), on the theory that your second PR into a codebase you know is likelier to land than your first into one you don't. On by default, TTY-only (piped output is byte-identical to before), and fully off withTERMINALHIRE_NO_CONTINUITY_RANK=1. The re-rank is computed locally from your own claim ledger.claim submitnow reports an acceptance forecast for the PR it just opened. A merge-probability estimate with its reasons (tests touched, files changed, diff size), computed locally from your diff and recorded on the claim so you can compare the forecast against what actually happened. It runs after the PR is opened and is advisory only — it never blocks or gates a submit, and any scorer error is swallowed rather than failing a submit that already pushed. Also fixes a real tracking bug: a PR that was closed and later reopened-and-merged is now correctly recorded as merged instead of being stuck atabandoned.- The acceptance credential no longer counts content-farm merges. A merged PR
that just appends a numbered entry to a data file ("Add new Japanese Proverb 149")
is not a coding merge, so it no longer inflates the credential computed at
terminalhire login. The gate is deliberately narrow — only the distinctive numbered-seed farm signature drops, and real translation/i18n code work is kept — because a false drop silently erases proof of a merge you actually earned. - Hardening: everything under
~/.terminalhireis now written0600/0700. Your claims ledger, encrypted profile key, and GitHub token are created with restrictive modes rather than whatever your umask happened to be, and re-login no longer leaves the token file at its old looser permissions. - Hardening:
claims.jsonis safe under concurrent writers. The background refresh monitor and an interactiveclaimcommand can no longer interleave and corrupt the ledger; writes go through an on-disk mutex with unique temp names, and a stale lock self-heals after ~10s. repooutput now suppresses personalized continuity/calibration lines when piped, matchingclaim listandclaim status.- Copy: the beta welcome no longer frames this as a résumé replacement ("your résumé tells the story; this backs it up"), and compute-location claims are stated as the guarantee we actually make — your profile never leaves your machine.
v0.33.0 — 2026-07-14
contributeandbountiesnow show what you've already claimed. An opportunity you hold an active local claim for is badged● claimed by youin the list, and its call-to-action swaps fromterminalhire claim <ref>toterminalhire claim status <id>— so a re-scan tells "I'm already on this" apart from "open," and points you at the right next command instead of the one that errors on a duplicate claim. The join is fully local (your claims ledger, matched by exact id) and the badge is distinct from the⚠ N PRs in flightcontention marker, which flags competition from other devs.
v0.32.0 — 2026-07-14
- Repeat invocations now rotate what you see. The same top matches no longer
pin themselves to every refresh:
devsdirectory: the top 5 stay stable, the rest of the list rotates through the full matched pool on a 5-minute window — and the directory now ranks the complete pool, fixing a bug where the list silently shrank to 9 entries.- Role matches: the previously permanent top-8 head now cycles hourly through the top-12 pool, so the head itself varies instead of only the tail. Ranking and privacy are unchanged — rotation reorders locally over the same locally-computed matches.
- Test hardening: the refresh-monitor version-handover test no longer flakes on slow CI runners (it now accepts both valid shapes of the legacy monitor's termination).
v0.31.1 — 2026-07-13
- Hardening: policy-audit excerpts are sanitized before display. The verbatim
CONTRIBUTING.md/AGENTS.md excerpts shown at
claim record/previeware attacker-controlled text (the target repo writes them). Control characters other than newline and tab are now stripped at excerpt creation, so an embedded ANSI or OSC escape sequence can't clear your screen, write your clipboard, or otherwise act on the terminal from the exact code path meant to make you read a repo's policy. Classification is unaffected. (Flagged in post-merge review of v0.31.0.)
v0.31.0 — 2026-07-13
- The claim-time policy scan now classifies instead of just flagging.
claim record/previewaudit the repo's CONTRIBUTING.md, AGENTS.md, and PR template and return a verdict —prohibited(repo bans AI-generated contributions),disclosure-required,ai-mentioned, orclean— plus the contribution requirements they state (assignment expected,/takebot, CLA, discussion-first), each with the verbatim excerpt so you read the repo's actual words, not our paraphrase. - A
prohibitedverdict gets a dedicated gate. The generic--ack-policyno longer clears it; recording the claim takes an interactive confirm (or the explicit--ack-policy-prohibitedflag) that spells out that everything you submit must be hand-written. The /claim skill is required to put that decision to the human — it can't self-attest past a ban. - The assignment request at
claim startis now audit-driven and previewed. The comment is only posted when the repo's docs actually expect it (/takeon bot repos, a plain request otherwise — including bots detected by the audit, not just the built-in list); repos with no stated expectation get no comment (pass--assignto request anyway). On an interactive terminal you see the exact comment body and confirm before it posts, and the copy has been de-botified. Claims recorded before this release keep the old always-post behavior. - Prompted by a real incident: a claim on a repo that prohibits AI-generated contributions auto-posted a public assignment comment. This release makes that combination impossible without a deliberate human yes.
v0.30.2 — 2026-07-13
- Internal cleanup: dropped the local click-tracking hop behind job tip links. Now that every statusline tip link points straight at terminalhire.com (v0.30.1), the loopback server the background monitor used to record a click locally before redirecting was dead weight — it's been removed end to end. Nothing changes in what you see or how clicks are counted (the public link still logs the click server-side); it's just one fewer moving part running in the background.
v0.30.1 — 2026-07-13
- Job tip links always show terminalhire.com. The role and bounty links in the
statusline now consistently point at
terminalhire.com/j/…instead of occasionally surfacing a bare127.0.0.1address that looked broken. Clicking tracks exactly as before — the public link records the click server-side.
v0.30.0 — 2026-07-13
claim audit <id>— a read-only look at a claim's PR lifecycle. A new command that walks a contribution claim's pull-request history — review rounds, state changes, merge outcome — and prints a stateless audit pulled fresh from GitHub. Nothing is scored and nothing is stored; it's the first step of the contributor- reputation work.
v0.29.0 — 2026-07-13
- A nudge when your dashboard's claim count is behind. If you push your claims to
the terminalhire dashboard manually, the CLI now tells you — in
claim listand ambiently in the statusline — when your local claims have moved on since your last push, so your public "merged" count doesn't silently lag reality. It points you atclaim --push --keep-updated, which keeps the dashboard in sync automatically from then on. Devs already on auto-sync never see it, and it reads only local files — nothing new leaves your machine.
v0.28.0 — 2026-07-11
- Claiming asks for the assignment, automatically.
claim startrequests assignment on the issue as part of provisioning —/takeon repos with a self-assign bot, a plain-English request everywhere else — so you follow the repo's "get assigned before you open a PR" etiquette without having to remember it. It's idempotent (won't double-post if you're already assigned or already asked) and best-effort (an unauthenticatedghor a network hiccup warns, never blocks your work). claim submitblocks a duplicate PR before you open one. If someone else already has an open pull request against the same issue,submitnow stops with an explanation instead of letting you ship a PR a maintainer will just close — the hard lesson from a race lost mid-build. Your own fork's PR never trips it, and an uncertain or degraded read never blocks (it stops only on a confirmed competing PR).--force-competingis there if you've decided to proceed anyway.
v0.27.0 — 2026-07-11
- One command to start a claim:
terminalhire claim start. After you claim an issue,claim startnow provisions the whole workspace end to end — fork, clone, branch, and attach — in a single step, replacing the oldattach --worktree … --branch …ceremony. It clones into a managed directory and simply prints thecdfor you; it never touches your current shell, cwd, or branch. Run it bare to pick from your claimed issues, or--herewhen you're already in the target repo.submitnow self-advances from the working state, so the interimupdate <id> readystep is optional.
v0.26.2 — 2026-07-10
- Clearer error when you tack an extra word onto a claim shortref. Running
claim <shortref>with a stray trailing argument (e.g. a pasted issue title) no longer bails with a generic message — it now points you at the exact command it thinks you meant, so you can fix the typo without re-reading the help.
v0.26.1 — 2026-07-10
claim <shortref>just works. Typing a claim shortref with no verb in front of it used to be rejected as an unknown command; it now routes straight toclaim record, matching how the rest of the CLI treats a bare identifier.
v0.26.0 — 2026-07-08
- Jobs you've already opened stop coming back. When you click a job link from the statusline tip (or anywhere the CLI surfaces one), that click is now recorded locally, so the same listing doesn't keep resurfacing on your next refresh. The jobs you've engaged with move out of the "new" surface and stay reachable in your Viewed history — nothing is lost, it just stops nagging you. (A click isn't an application, so it's tracked as Viewed, not Applied — the distinction is preserved on purpose.)
- Still 100% local — that's the point. Which jobs you clicked is recorded on
your machine only. The click still redirects through
terminalhire.com/j/…so the anonymous click analytics we already collect are unchanged, but which job it was never leaves your machine — there's no server-side record of your job history to leak, subpoena, or breach. The background refresh monitor listens on127.0.0.1only; no new network access.
v0.25.0 — 2026-07-07
- Claimable work is now ranked by how winnable it is, not how it's priced.
bountiesand the hub's Bounties pane surface open-source issues ordered by a winnability signal — an active maintainer who actually merges outside pull requests, low contention, recent activity, and a match to your local vocab — so the top of the list is the work you're most likely to get merged, not just the loudest listing. A repo with big stars but a history of never merging external PRs no longer floats to the top. (Ranking is computed server-side and shipped in the index; the CLI still ranks locally with zero egress.) - Paid public bounties are paused by default. Every paid public bounty we
surfaced turned out to be spammed-out, already-done, or not real, so they're
hidden from the default surface for now — nothing is deleted and the claim
flow is unchanged. Run
bounties --pricedto see them, or reach forterminalhire contributefor merge-ready open-source work. We'll bring paid bounties back when we have more say in their quality. - Repo discovery for the contribute feed. The contribute feed now seeds high-traction candidate repos (trending ∪ vocab-adjacent) and surfaces their open good-first-issue / help-wanted issues, scored by the same winnability pipeline — widening supply beyond what you've already touched.
- Maintainer/Founder credential (web). If you started a project that enough outside contributors build on, your resume card and dashboard now show a reach-only "Maintainer" credential. (Surfaces on the web dashboard; the bundled matching engine carries the supporting signals.)
v0.24.1 — 2026-07-06
- Hub mouse support. In the full-screen
terminalhire hubTUI you can now click a nav-rail section to select it, or click a Jobs/Bounties row to open it. The hub stays keyboard-native; mouse is purely additive. (Mouse capture disables native terminal text-selection unless you hold Shift, or Option on macOS Terminal/iTerm.)
v0.24.0 — 2026-07-06
- Better matching for what you're aiming at. Your stated project aspiration now persists across runs and feeds a three-tier vocabulary graph, so matches track the work you want to be doing, not just what you've done.
v0.23.0 — 2026-07-06
terminalhire hub— a full-screen, keyboard-native TUI. One running app that unifies jobs, bounties, connect, the chat inbox, claims, and your profile behind a nav rail and command palette. Every existingterminalhire <command>keeps working exactly as before — the hub is additive, zero new dependencies, and still 100% local.
v0.22.0 — 2026-07-06
- Frictionless claim submit + contention watch. Submitting a claimed bounty PR is smoother, and you can now see when others are racing the same issue — comment fast, win the merge.
v0.21.0 — 2026-07-05
- Passive interest capture at
init— the matcher learns what you're drawn to without any extra input, and adds a disjoint "Stretch" job slot. - Claim-sync robustness improvements.
v0.20.0 — 2026-07-05
- Interactive update prompt, a minimum-value bounty floor, a scope-C "Stretch" slot, and a dashboard claim view (with opt-in periodic background push).
v0.19.x — 2026-07-05
- v0.19.2 — Beta daily pulse: a light 0–3 question micro check-in.
- v0.19.1 — Feedback quick-form + a listener fix.
- v0.19.0 — Surfacing upgrades (soft tags + MMR re-ranking for variety), a contribute-quality classifier, claim hardening, and the beta program.
v0.18.x — 2026-07-03 → 07-04
- v0.18.2 — Spinner engagement-suppression (quieter when you're heads-down).
- v0.18.1 — Feed-text sanitizer + unified bounty effort thresholds.
- v0.18.0 — Thin-profile contribute on-ramp — start contributing before your profile is fully built out.
v0.17.x — 2026-07-03
- v0.17.2 — Session-stale link fix + clearer CLI labels.
- v0.17.1 — Apex-domain hotfix.
- v0.17.0 — Harness expansion: the terminalhire MCP server (use it from any AI editor) plus a VS Code / Cursor / Windsurf status-bar extension.
v0.16.x — 2026-07-02
- v0.16.1 — Inbox UX polish.
- v0.16.0 — Interactive inbox TUI.
v0.15.0 — 2026-07-02
- Hardening train — stability and correctness across the CLI.
v0.14.0 — 2026-07-01
- Spinner content freshness — anti-repeat and wider variety in the ambient surface.
v0.13.0 — 2026-07-01
- Contribute — a feed of credential-building open-source issues — plus the recruiter-legible credential projection.
v0.12.0 — 2026-07-01
- Connection notifications in the Claude Code status line.
v0.11.x — 2026-07-01
- v0.11.1 — Chat presence-integrity fix.
- v0.11.0 — Presence → reachability refinements.
v0.10.x — 2026-06-30 → 07-01
The connections + chat train:
- v0.10.11 — Presence becomes "reachability" + consented activity + a session self-diagnostic.
- v0.10.10 — Pending invitations in the chat inbox + an inline picker.
- v0.10.9 — Badge correctness (single monitor, read-clears-badge).
- v0.10.8 — Fix connection badges silently dying (apex→www cookie strip) + a loud session-expiry hint.
- v0.10.7 — Chat uses the alternate screen buffer (no more frame stacking).
- v0.10.6 — Connection badges always show (no longer nudge-gated).
- v0.10.5 — Unread-messages badge in the status line.
- v0.10.4 — Chat-first contact (lead with chat; handle as the default).
- v0.10.3 — Intros work with just a GitHub username (no email required).
- v0.10.2 — Connect follow-ups: devs self-filter, sender view, disclosure.
- v0.10.1 — Frictionless intro accept.
- v0.10.0 — Connect-loop hardening: inbound nudge, dashboard, honesty + staleness.
v0.9.x — 2026-06-30
- v0.9.2 — Fixes.
- v0.9.1 —
terminalhire link— bridge a CLI session to the web. - v0.9.0 — 1:1 end-to-end encrypted connections chat + an inline reader.
v0.8.0 — 2026-06-30
- Ambient peer / founder surfacing, behind an opt-in gate.
v0.7.x — 2026-06-30
- v0.7.1 — Fixes.
- v0.7.0 — Two-sided match + consented connection (the intro flow).
v0.6.0 — 2026-06-29
terminalhire claim submit+attach— claim a bounty and attach your PR.
v0.5.0 — 2026-06-27
terminalhire trajectory(with MCP-name redaction).
v0.4.x — 2026-06-16 → 06-27
- v0.4.6 — Sign into the website automatically after CLI GitHub login.
- v0.4.5 — Styled, confirm-before-claim preview.
- v0.4.4 — Installer pin.
- v0.4.1 — Spinner leads with roles, bounties secondary.
- v0.4.0 — Proof-of-Work acceptance credential — your merged PRs as a verified competence signal.
v0.3.x — 2026-06-15
- v0.3.5 — Neutral spinner verbs.
- v0.3.4 — Rotate + alternate bounties so several show, not one.
- v0.3.3 — Bounties lead the verb + tip.
- v0.3.2 — Guarantee bounty slots.
- v0.3.1 — Bounty-aware ambient surface.
- v0.3.0 —
terminalhire bounties.
v0.1.0 – v0.2.5 — 2026-06-14 → 06-15
- Initial releases: the local-first job matcher and ambient Claude Code spinner surface. Started life as the "Hireline" MVP, rebranded to terminalhire with GitHub OAuth, auto-learning, and hybrid matching. Your profile has never left your machine — from day one.