Documentation
How the cloud is weighted, the API and MCP server, two worked runs, and embedding. Sections fold; the outline follows you.
On this page
How skill spheres are weighted
Every skill in a cloud has a depth between 0 and 1, shown as a score out of 10. The sphere's size follows that depth, so a cloud can be read at a glance: big spheres are what the person is deep in, small ones are working knowledge or interests.
Where depth comes from. When a cloud is built from a résumé, depth reflects evidence in the text, not self-assessment: repeated, senior, long-running work on a topic scores high; a single mention scores low. Roughly: 2/10 is a mentioned interest, 5/10 working knowledge, 8/10 deep sustained experience, 9.5/10 expert-level evidence across many contexts.
The depth budget. The total depth across a cloud is capped by experience: a cloud earns a budget of min(18, 3 + 1.1 × years) total points, where years is the person's estimated professional experience. If a cloud's skills add up to more than the budget, every depth is scaled down proportionally. That is why adding skills dilutes the rest: nobody is 10/10 in a hundred topics, and the budget makes breadth visibly trade off against depth.
Manually added skills. When you add a skill yourself (in your cloud, or claiming one from a project), you state your years of hands-on experience with it and the depth follows 0.15 + 0.09 × years, capped between 1.5/10 and 9.5/10, so about 4 years lands at working knowledge and about 7 years at deep experience. The skill is marked as manually added, and the overall budget still applies afterwards.
Versioning. Clouds carry the version of the scoring method that built them. When the method improves, older clouds show a rebuild notice so their scores stay comparable with everyone else's.
Connect Claude Code, Codex or Claude Desktop
Most people use PairHarbor from the agent they already run. PairHarbor ships an MCP server, so Claude Code, Codex, Claude Desktop or any other MCP client can read and update your cloud and work inside your workspaces as tools: you say what you want, the agent makes the call. It authenticates with a personal API token and talks to the v1 API below, so every safety filter, membership gate and write limit applies unchanged.
- Create an agent for this machine in Settings (Agents), press New token, and export the token as
PAIRHARBOR_TOKENin your environment. Never commit it. - Register the server with your client. The package is
pairharbor-mcpon npm and needs Node 20 or newer;npxfetches it on first use. Claude Code reads.mcp.jsonin the project (or your user settings); Codex reads~/.codex/config.toml. The server runs on your machine and only calls this API with your token.
{
"mcpServers": {
"pairharbor": {
"command": "npx",
"args": ["-y", "pairharbor-mcp"],
"env": { "PAIRHARBOR_TOKEN": "ph_your_token" }
}
}
}Or one command, no file: claude mcp add pairharbor -e PAIRHARBOR_TOKEN=ph_your_token -- npx -y pairharbor-mcp
Then talk to it. Every request sample in this document has a “Claude Code / Codex” tab with the sentence to type; the agent picks the tool and makes the call as you.
Tools, as in the package README. Your cloud: whoami, get_my_cloud, update_my_cloud, add_skills, remove_skills. Workspaces and projects: list_workspaces, get_workspace_usage, list_workspace_projects, post_workspace_project, post_public_project, update_public_project, delete_workspace_project. Tasks and agents: list_my_tasks, list_workspace_tasks, get_task, create_task, approve_task, claim_task, update_task, complete_task, suggest_assignees, wait_for_tasks. Every tool acts as you, and task history names the agent whose token was used. There is deliberately no extraction tool: mapping a résumé or a project description stays in the signed-in app, and the tools take ready-made skills.
Plan a project from your agent
With the server connected, planning a workspace project is a conversation, covered by the subscription you already pay for. Ask for the plan first, then for the filing:
Plan the project "<title>" in my <workspace> workspace on PairHarbor.
Read its brief, skills and terms, suggest who covers each task, and show me
the plan. When I say "file them", create the tasks.The agent uses the same tools you would (list the project, suggest assignees, create tasks). Tasks it files are proposals until a member approves them, or go live at once if the workspace runs unattended mode.
Claude Desktop: one-click bundle
Claude Desktop installs local MCP servers from a bundle file, so there is nothing to type. Download pairharbor-mcp.mcpb (version 0.5.6, the same server as the npm package), open it with Claude Desktop, and paste your token into the “PairHarbor API token” field of the install dialog. Claude Desktop stores the token securely and starts the server on your computer whenever a chat needs it; the server only calls this API. Use a token from the agent you created for that computer, so its actions are recorded under that name.
API
The same calls the MCP server makes, for scripts and other clients. A personal API token reads and writes your own cloud, nothing else. There is no extraction endpoint: building a cloud from a résumé stays in the signed-in app, and the API takes ready-made skills. If you connected an agent above, you already have a token and can skip step 1.
1. Create a token
- Open Settings and scroll to Agents.
- Create an agent named after the machine the script will run on (“Work laptop”, “Build box”) and press New token on its row. A token acts as you; what it does is recorded under the agent's name.
- Copy the
ph_...value immediately. It is shown exactly once; we store only a hash. Treat it like a password. - Revoke a leaked or retired token in the same list at any time. You can hold up to 5.
Every request authenticates with the token as a bearer header: Authorization: Bearer ph_your_token
2. Read your cloud
GET /api/v1/cloud returns your private cloud: title, skills with depth and category, estimated years, scoring version, and last update time.
Show me my PairHarbor cloud: title, skills with their depth, and years.Needs the server from Connect Claude Code, Codex or Claude Desktop. The agent calls the tool as you.
Response:
{
"title": "John D. · AI Engineering Leader",
"skills": [
{ "name": "Postgres Tuning", "depth": 0.72, "category": "engineering" },
{ "name": "Team Leadership", "depth": 0.55, "category": "trait", "manual": true }
],
"years": 8,
"version": 2,
"updatedAt": "2026-07-31T10:00:00.000Z"
}3. Import or update your cloud
PUT /api/v1/cloud replaces your cloud's skills (and optionally its title) with what you send. Useful for keeping PairHarbor in sync with a skills file you maintain elsewhere.
Replace my PairHarbor cloud with these skills and call it "My imported cloud":
Rust 0.8 engineering, Causal Inference 0.6 domain, Team Leadership 0.5 trait.Needs the server from Connect Claude Code, Codex or Claude Desktop. The agent calls the tool as you.
Response:
{ "ok": true, "skills": [ ...the normalized result... ] }Rules applied to every write: categories are engineering, domain, product, craft, and trait; depths are clamped to 0–1; skill names pass the same safety filters as everywhere else (no emails, credentials, or personal data); and the depth budget re-normalizes the result when your cloud's years are known, so totals stay proportional to experience. The response contains the cloud as actually stored; read it back rather than assuming your input survived unchanged.
4. Account and workspaces
The same token also answers who it belongs to and reaches the workspaces the account is a member of. All of these are scoped exactly like the app: you see only your own account and the workspaces you are in.
GET /api/v1/me # owner id, provider, display name, email, cloud title
GET /api/v1/workspaces # Public first (kind "public"), then your company workspaces
# (kind "company"; invite token on admin rows only)
GET /api/v1/projects # your PUBLIC projects: handle, url, listed, skills, brief
POST /api/v1/projects # { title, skills, brief?, employment?, workModes?, country?, city?, list?, teamMin?, teamMax?, startsOn?, endsOn? } -> a public project page, unlisted unless list: true; the brief is public on the page
PATCH /api/v1/projects # { handle, brief } set or clear ("") your public project's brief
GET /api/v1/workspaces/<id>/projects # a company workspace's projects (members only)
POST /api/v1/workspaces/<id>/projects # { "title", "skills", "brief"?, "teamMin"?, "teamMax"?, "startsOn"?, "endsOn"? }, ready-made skills; the brief is kept with the project
DELETE /api/v1/workspaces/<id>/projects?id=<projectId> # poster or adminPublic is the first workspace in the list on purpose: it is the open site, so “which workspace am I in” always has an explicit answer. Posting a public project creates a public page, so it stays unlisted unless you pass list: true, and its brief is shown on that page. Deleting one stays in the app.
5. Tasks and agents
Inside a company workspace, projects split into tasks assigned to members. An agent is a machine, VM or container you run, created under Settings; its tokens act as you, so a script or Claude on that machine sees your workspaces, your task inbox and your cloud, and every change it makes is recorded under the agent's name. The workspace routes below accept either your signed-in session or one of your agents' tokens, so people and their machines use one API.
GET /api/v1/tasks?status= # tasks assigned to you, across workspaces (an agent's inbox)
GET /api/org/<id>/tasks?projectId=&status= # a workspace's tasks
POST /api/org/<id>/tasks # { projectId, title, description?, skills, assignee?, dueOn? } (dueOn defaults to the project's end date)
GET /api/org/<id>/tasks/<taskId> # one task with its audit trail
PATCH /api/org/<id>/tasks/<taskId> # { claim: true } | { status } | { assignee } | { report, artifacts } | { approve: true } | edits
POST /api/org/<id>/tasks/suggest # { skills } -> members ranked by coverageTwo rules apply to calls made through a token, because nobody is watching the machine. A task created through a token is a proposal: it stays out of every inbox until a member approves it (PATCH { "approve": true }, optionally with a different assignee) or rejects it, which is how a machine can plan work unattended without anyone being surprised by it. And deleting a task needs a signed-in session. Everything else works the same both ways. When a task is completed, its required skills join the assignee's cloud: new ones at a modest depth, existing ones a little deeper, with a history entry saying so.
To have a machine work your tasks unattended, the npm package ships pairharbor-worker: a loop that pulls your assigned tasks, hands each to a handler (a coding handler that runs Claude Code on a repository branch, an Android emulator operator, or your own module), and reports back with a completion report or a blocked reason. Run it with one of your agents' tokens; the Set up panel in Settings and the package README show the commands.
Three workspace-level controls shape unattended work. A workspace admin can turn on unattended mode (Members, Automation) so tasks created through members' agent tokens go live at once instead of waiting as proposals; the history records the auto-approval. Workers get push delivery through GET /api/v1/tasks/wait?since=&timeout=, a long poll that returns as soon as a task assigned to the token owner changes (the MCP tool is wait_for_tasks; the worker uses it between passes). And admins can register webhooks: HTTPS endpoints that receive a JSON POST per task event with an X-PairHarbor-Signature header (HMAC-SHA256 of the body with the endpoint's secret), for server-hosted bots and integrations.
On trust: an agent always belongs to one person and acts within that person's own memberships, so a person in several workspaces serves all of them with one token and nothing crosses a workspace boundary that the person could not cross. Agents offered publicly, to workspaces their owner is not a member of, are deliberately not part of this design.
Plans: a workspace's plan (see pricing) sets how many members it admits, how many webhooks it may register, and how many tasks agents may mark done per calendar month. Tasks people complete are never counted. At the allowance, an agent's completion is refused with 402 and { "code": "quota" } until a person completes it or an admin upgrades; GET /api/org/<id>/billing (MCP: get_workspace_usage) reports the plan and what is left, so a planner can pace itself.
Errors and limits
| 401 | Missing or invalid token. Check the Authorization header. |
| 404 | GET only: you have no cloud yet. Build one in the app first. |
| 400 | PUT only: empty or invalid skills array, or malformed JSON. |
| 429 | Daily write limit reached: 100 writes per token per day. |
| 402 | Task routes only: the workspace's monthly allowance of agent task completions is used up (code "quota"). |
Worked examples
The same loop twice: post a project, split it into tasks, people take them, reports come back. The first run is a company workspace with a team of twelve and a fictional QA lead. The second is the Public workspace with nobody but you and Claude Desktop, and it is one you can follow along right now.
A company round: 12 Android testers for 14 days
One project from posting to done, the way a small company would run it. Nadia runs QA at a fictional maps startup, Trailhead. Their Android app ships a big release in two weeks and she needs it exercised on twelve real devices before it goes to Google Play. Everything below uses features that exist today; the names are made up.
1. The workspace
Nadia creates a company workspace called Trailhead under Workspaces and shares its invite link with the QA contractors she works with. Because the link is restricted to the trailhead.app email domain, only people signed in with a company address can join. Each tester builds a cloud from their résumé on My cloud and ticks “Share my skill cloud with Trailhead” on the Members page. Sharing is off by default; without it a tester is a member but invisible to the matcher.
2. The project
On the workspace's Projects tab she pastes the brief and PairHarbor extracts the required skills. From an agent or the API the same thing is one request with a ready-made skill list:
Post a project in my Trailhead workspace on PairHarbor titled
"Android release 4.2: 14-day device test" with skills: Android 0.8 engineering,
Mobile QA 0.9 craft, Bug Reproduction 0.8 craft, Regression Testing 0.7 craft,
Espresso 0.5 engineering, Google Play 0.5 domain.Needs the server from Connect Claude Code, Codex or Claude Desktop. The agent calls the tool as you.
Build team on the project card now answers her first question: which twelve members cover these skills best. The table ranks every shared cloud by depth-weighted coverage, so she can see at a glance who is strong on Espresso and who has never touched it.
3. Splitting it into tasks
When she posts the project she also states its terms: at least twelve people, from the 15th to the 28th. The card then reads “12 people · 14 days from Sep 15 · 0 of 12 committed”, Build team fills to twelve names instead of the smallest covering set, and every task created under the project is due on the 28th unless someone says otherwise. Fourteen days and twelve people is too much to hand out by hand, so Nadia asks Claude. She has the PairHarbor server connected in Claude Code (or Claude Desktop), which is included in her subscription, and types:
Plan the project "Android release 4.2: 14-day device test" in my
Trailhead workspace on PairHarbor. Read its brief, skills and terms,
check who covers what, and show me the plan before filing anything.Claude reads the project through the workspace tools, asks the matcher who covers each area, and answers with a plan: one task per person because the project says twelve, each with acceptance criteria and a suggested tester, no tester named twice. She reads it, asks for one change, then says “file them”.
1. Pixel 8 (Android 15): install, sign-in, cloud upload, share -> Priya 92%
2. Galaxy S24 (One UI 7): same flow plus dark mode and rotation -> Marcus 88%
3. Low-end device (Android 12, 3 GB): cold start under 4 s -> Wen 81%
4. Tablet layout (Tab S9): Harbor grid and project dialogs -> Ana 77%
5. Espresso smoke suite: run nightly, file regressions -> Diego 85%
6. Offline and flaky-network behaviour on any device -> Lena 74%
...
Say "file them" and I will create the twelve tasks as proposals, due Sep 28.The twelve tasks appear on the project's Tasks dialog as proposals. Because they were created through Claude rather than by hand on the site, nothing is assigned yet: a banner says twelve proposals await approval. Nadia approves ten as suggested, changes the assignee on one (Wen is on holiday, so Omar gets the low-end device), and rejects one that duplicated the Espresso suite. She adds an eleventh task herself: a daily triage of everything filed.
4. Testers take and do the work
Approved tasks land in each tester's inbox. Priya works the way most people will: she opens the Tasks dialog, sets her task to In progress, tests on the Pixel for a week, and when she is done sets it to Done with a report and links to the three bugs she filed. Every change is recorded in the task's history.
Marcus prefers Claude Desktop. With the one-click bundle installed and his own token pasted in, he asks “what PairHarbor tasks do I have?”, then “mark the Galaxy task in progress”, and at the end dictates his report: “complete it: dark mode fine, rotation loses the search text, filed as TH-311”. Claude calls the same tools and the team sees the same history, with “via Marcus's laptop” next to each entry.
Diego's Espresso task is the one a machine can run. He starts the worker on the lab PC that has the emulator:
npx -p pairharbor-mcp pairharbor-worker \
--handler android-emulator --workspace TrailheadThe worker pulls his assigned task, installs the build named in the task text, launches the app, runs a stress pass, reads the crash log, and completes the task with a PASS or FAIL report and screenshots. It then waits; when Nadia assigns him a re-test after a fix, the worker picks it up within a second, without anyone touching the lab PC.
5. What Nadia sees
The Tasks dialog is her status board: twelve rows, who has what, which are blocked and why, and which are past their due date, shown in red. The project card keeps the staffing line current: “11 of 12 committed” turns amber on the start date if the twelfth tester is still missing. Lena marks her offline task blocked with “test build 4.2.3 crashes on launch”, and that reason is visible to everyone. Nothing is deleted or reassigned without a signed-in member doing it, and the history of each task names every person and machine that touched it.
On day fourteen all tasks are done. One side effect is easy to miss: each completed task added its skills to the tester's own cloud, so Omar now has “Android” and “Bug Reproduction” on his profile from work he actually did, and the next Build team run ranks him higher.
Going further
If Trailhead runs this every release, Nadia can turn on unattended mode on the Members page so tasks Claude files go live without the approval step, and register a webhook so each completed task posts to their chat. Both are described in section 5 of the API reference above.
A public task from Claude Desktop, start to finish
Ten minutes, one account, nothing but Claude Desktop: you post a public project for testing the PairHarbor Android app, define a task under it, take the task yourself, and hand in the results. Each step is a sentence you type; the tool Claude calls is named so you can see what happened. It all runs in the Public workspace, so anyone signed in could have claimed the same task from the project's page.
How tasks work in the Public workspace
- Only the project's owner defines tasks. Created through Claude, a task is a proposal until the owner approves it.
- Anyone with an account sees a public project's open tasks (the Tasks button on its page) and can claim one. Nobody is assigned by someone else, and one account holds at most five unfinished tasks on other people's projects.
- The report, its links and the history are between the owner and whoever did the task. Other visitors see open tasks only.
- Agents can complete up to 50 tasks a month across one owner's public projects. Tasks people complete are never counted.
0. Connect Claude Desktop
In Settings, under Agents, create an agent for this computer and press New token. Download pairharbor-mcp.mcpb, open it with Claude Desktop and paste the token into the install dialog. If you installed the bundle before version 0.5.6, install this one over it so Claude knows tasks work in Public. Then check the connection:
Who am I on PairHarbor, and which workspaces can I act in?Claude calls whoami and list_workspaces and answers with your account and a list that starts with Public.
1. Post the project
Post a public project on PairHarbor called "PairHarbor Android app: test round".
Brief: we are testing the Android app (package com.pairharbor.app) on real
phones before it goes to Google Play production. Testers install it, sign in,
build or open a skill cloud, and report what broke.
Skills: Android 0.6 engineering, Mobile QA 0.8 craft, Bug Reproduction 0.7 craft,
Attention to Detail 0.6 trait. It is a short remote project ending in 14 days.
Keep it unlisted for now and give me the link.Claude calls post_public_project and returns a link like pairharbor.com/u/ab12cd34. The last part is the project's handle; tasks hang off it. Unlisted means only people with the link see the page. To let strangers find it, switch on its Harbor listing on the Projects page.
2. Define the task
Create a task under that project in the Public workspace:
"Install the app and run the first-launch checklist".
Description: 1) install the app from the Play testing link, 2) confirm it opens
full screen with no browser address bar, 3) sign in with Google, 4) open My cloud
and rotate the 3D cloud, 5) open a shared link to pairharbor.com and confirm it
opens in the app, 6) press Back from each screen. Report phone model, Android
version, and anything that failed, with screenshots.
Skills: Mobile QA 0.8 craft, Android 0.5 engineering. Leave it unassigned.Claude calls create_task with workspace public and the project's handle. The task comes back with status proposed: it exists, but nobody else can see it yet.
3. Approve it
Approve that task so it is open.Claude calls approve_task. The task is now open: it shows under Tasks on the project page for every signed-in visitor, and anyone could claim it. This is the step that makes work Claude filed real, and it is always yours.
4. Take the task
Claim that task for me and mark it in progress.Claude calls claim_task and then update_task. Ask “what PairHarbor tasks do I have?” and it appears in your inbox (list_my_tasks), marked as belonging to the Public workspace.
5. Do the work
This part happens on your phone, not in Claude. Run the six checks from the task and note what you see. If something stops you, say so instead of guessing: “mark the task blocked: the testing link says the app is not available for my account” records the reason where the owner will read it.
6. Hand in the results
Complete the task with this report: Pixel 8, Android 15. Installed from the
testing link, opened full screen, Google sign-in worked, cloud rotated smoothly.
One problem: Back from the Harbor closed the app instead of returning to My cloud.
Attach https://example.com/screenshots as "Screenshots".Claude calls complete_task. The task is done, the report and the link are stored with it, and the task's skills are added to your own cloud as evidence of work you did.
7. Read it back
Show me that task with its full history.Claude calls get_task and lists every step with its time and the name of the agent that made it: proposed, approved, claimed, in progress, done, reported. The same history is on the web: open the project page, press Tasks, and select the task.
With other people
You played both parts. In a real round you stop after step 3 and send the project link to your testers. Each one signs in, presses Tasks on the page, claims a task and submits a report there, or asks their own Claude to do it. You see their reports; they never see each other's. When a round needs private briefs, named assignees or more than 50 agent completions a month, run it in a company workspace instead, as in the company round above.
Embed a cloud in your website
Every published cloud has an iframe-friendly page at /u/<handle>/embed: the interactive 3D scene alone, no site chrome, with a small PairHarbor mark linking back to the full page.
- Publish your cloud (the share button on My cloud). You get a link like
pairharbor.com/u/ab12cd34. - The handle is the part after /u/. Append /embed to get the embeddable page.
- Paste the iframe below into your site's HTML.
<iframe
src="https://pairharbor.com/u/YOUR_HANDLE/embed"
width="100%"
height="480"
style="border: 0; border-radius: 12px"
loading="lazy"
title="My skill cloud"
></iframe>For a responsive embed that keeps its shape on phones, wrap it in an aspect-ratio box instead of a fixed height:
<div style="aspect-ratio: 16 / 9; max-width: 900px">
<iframe
src="https://pairharbor.com/u/YOUR_HANDLE/embed"
width="100%"
height="100%"
style="border: 0; border-radius: 12px"
loading="lazy"
title="My skill cloud"
></iframe>
</div>Append ?mode=genesis to the embed URL to play the cloud as the Genesis animation (the skills accreting into orbit like a forming solar system, looping) instead of the static sphere.
Good to know: the embed shows exactly what the public page shows, nothing more. It does not need the cloud to be listed in the Harbor, only published. The page is live, so skill edits and renames appear in the embed automatically; revoking the link in Settings kills it. Visitors' browsers render the scene locally with WebGL; browsers without it see a plain fallback. Any site that allows iframes works, including Notion, WordPress, and personal sites.
GitHub README and other no-iframe sites
GitHub profile READMEs (and platforms like dev.to) strip iframes, but they render images. Your cloud's preview card is an image, so this Markdown gives you a branded, clickable card that lands on the live 3D cloud:
[](https://pairharbor.com/u/YOUR_HANDLE)The card regenerates from your current cloud; GitHub caches images for a few hours, so edits take a little while to appear there.
Questions the docs don't answer? See the privacy policy for how data is handled, or the terms.