paigy
OfficialPaigy is an MCP server that lets AI agents reach the user by phone/notification when they need input, and manage durable goals, replies, and pairing.
contact: Send the user questions with optional options/previews, via notification or a ringing call; supports confirm, one/many/ranked choices, or free-text replies, with urgency levels like inbox, push, banner, or call.
check_replies: See everything waiting for you — open deliveries, unstarted assigned goals, and goals with new user activity; reading does not consume anything.
create_goal / claim_goal / get_goal / update_goal: Create durable outcome-based goals, claim ownership of runnable or stalled goals, read goal details and conversation, and update state, progress, title, dependencies, children, or review acknowledgments with stale-revision protection.
onboard / pair / unpair: Set up the agent's identity, pair it with the user's Paigy account (including fast-path device credential hatching or code-based pairing), rename/choose voice, or unpair and revoke tokens.
listen: Check whether the agent is listening for incoming answers and get the exact background command to start listening if it isn't.
Stalled-work handling: Automatically surfaces goals with no progress for three days at session stop, and returns stalled items via check_replies or the listener.
Pairs with the native Paigy iOS app to receive calls (via CallKit), banner notifications, and reply from the lock screen, integrating the user's iPhone as an interface for agent notifications.
Allows local AI models running via Ollama to use Paigy for notifying users and awaiting replies through phone calls, banners, or push notifications.
Paigy — MCP server
A voice inbox for your AI agents. When an agent needs your input — mid-task, blocked, or done with something long-running — it can place an actual phone call and read the question aloud, text, push, or ring your phone with a banner, so you can reply by voice instead of babysitting a terminal.
Without Paigy, a long agent session means one of two bad options: sit and watch the terminal so you don't miss the moment it needs you, or walk away and come back to a task that stalled an hour ago waiting on a question you never saw. Paigy closes that gap — the moment your agent actually needs a decision, your phone gets pulled into the loop with the level of urgency that matches the moment (a silent inbox card, a quiet push, a banner, or a real ringing call), so you find out immediately instead of on your next check-in. Answer by voice or text and the reply lands back with the agent exactly like any other tool response, so it just continues — no copy-pasting, no reopening the terminal. It also pairs with the native Paigy iOS app, so a call rings through like a real phone call (CallKit) even when your phone is locked, and you can glance at or reply to anything from the lock screen.
Works with
A standard MCP server (stdio, TypeScript) — no client-specific code anywhere, verified over the raw protocol against a non-Claude client identity.
Claude Code (this repo is also the plugin + marketplace for it)
Codex CLI
Gemini CLI
Any other MCP client via standard config: Cline, Continue.dev, Zed, Cursor, Goose, mcphost — including local-model setups over Ollama, LM Studio, or llama.cpp
(The app + backend live in a separate repo.)
Related MCP server: Switchboard
Install
One line, any terminal — detects your agents (Claude Code, Codex,
Antigravity), wires Paigy into each, and pairs your phone once. Prints every
command before running it; --dry-run shows the plan:
curl -fsSL https://paigy.ai/install | shPrefer to do it by hand? Pick your client below.
Claude Code (plugin — easiest path on Claude):
/plugin marketplace add paigy-ai/mcp
/plugin install paigyConnects automatically; the first time an agent uses it while unpaired, it'll
prompt you to pair — run /paigy-onboard (opens your browser to approve).
Claude Desktop (MCPB bundle — no terminal needed):
download paigy.mcpb,
then in Claude Desktop open Settings → Extensions and drag the file in (or
double-click it). Ask Claude to "pair with Paigy" — it runs pairing itself and
shows a code to approve on your phone. Also on
Smithery.
Codex CLI:
codex plugin marketplace add paigy-ai/mcp --ref main
codex plugin add paigy@paigy-ai
npx -y -p @paigy/mcp@latest paigy-mcp-onboardThe plugin configures the Paigy MCP server and includes guidance for calls, replies, and callbacks. Start a new Codex session after installation.
Codex CLI — direct MCP fallback:
codex mcp add paigy -- npx -y @paigy/mcp@latestThen forward Codex's thread id into the server, so each Codex conversation gets its own
Paigy identity — Codex builds the MCP server's environment from a fixed allow-list, so a
variable it isn't told to pass never reaches us. Add this line under [mcp_servers.paigy]
in ~/.codex/config.toml (paigy-harness setup does it for you):
env_vars = ["CODEX_THREAD_ID", "CODEX_SESSION_ID"](Don't pass it as a -c override on mcp add — that lands before the block is written
and Codex rejects the half-table with "invalid transport", writing nothing.)
Gemini CLI:
gemini mcp add -s user paigy npx -y @paigy/mcp@latestAny other MCP client (Cline, Continue.dev, Zed, Cursor, or a CLI that
takes the standard MCP JSON config directly) — most GUI clients take this in
their MCP settings (Cline: cline_mcp_settings.json; Continue:
~/.continue/config.json):
{
"mcpServers": {
"paigy": {
"command": "npx",
"args": ["-y", "@paigy/mcp@latest"]
}
}
}Then pair your phone:
npx -y -p @paigy/mcp@latest paigy-mcp-onboardEach session hatches its own identity automatically the first time it reaches Paigy —
no agent name to set or match. (Set PAIGY_AGENT=<name> only if you deliberately want a
client to always speak as one fixed named identity; then run onboard with the same name.)
Approve on your phone, then sign in at paigy.ai to start
receiving messages.
Heads-up for smaller/local models: the tool descriptions ask the agent to pick between a few answer shapes (confirm, options, free text) based on context — Claude follows this reliably; smaller local models may be less consistent about it. Free text always works as a fallback.
Choosing how the user answers
notify_user should ask in the shape that's fastest to answer — don't leave a
decision as free text. Pick with select (and options):
You need… | Use | Answer comes back as |
Yes/No or Approve/Deny |
|
|
Pick one of several |
|
|
Pick several |
|
|
Rank / order a subset |
|
|
A visual choice | options with an | one of the above |
An open-ended reply | no options |
|
confirm is answerable straight from the banner (Yes/No or Approve/Deny
buttons). Other paiges get banner actions See Options · Hear them · Remind me
later.
urgency is a request, not a guarantee — the user's account settings can
cap it lower. Four levels, low to high: "inbox" (silent, sits in the inbox),
"push" (a quiet passive notification, no sound), "banner" (a
time-sensitive lock-screen banner with sound), "call" (rings the phone —
use only when you genuinely need the user in the moment).
If you're about to start something long-running or blocking — the kind of thing where the user would otherwise sit and wait on you — mention once, in passing, that you can text or call them when it's done or if you hit a blocker. Don't offer it for quick tasks, and don't repeat the offer once they've answered.
Stalled work (automatic, no setup)
When a session stops and its agent owns Paigy Goals with no progress for three days, a Stop
hook holds the stop once a day and lists them, so the agent updates, finishes or cancels
each before it goes quiet. It runs paigy-stalled from @paigy/mcp (0.40.15 or later) and is
silent otherwise: nothing stalled, a stop already being continued by a hook, a reminder already
given that day, or any error. One script, the same hook in each harness's plugin:
Claude Code —
hooks/hooks.json, wired by the plugin; nothing to set up.Codex CLI —
plugins/paigy/hooks/hooks.json, wired by the Codex plugin. Codex runs a plugin's hooks only after you trust them: review and trust the Paigy hook when Codex asks.Any other harness with a Claude-style Stop hook — register
npx -y -p @paigy/mcp@latest paigy-stalledas the Stop command. It reads the hook's JSON (session_id,stop_hook_active) on stdin and prints{"decision":"block","reason":…}.
Hosts with no hooks still get the list: check_replies (which the server's instructions tell
every agent to call on startup and after a wake) returns it under stalled, and paigy-listen
carries it in the work it hands a session it wakes.
License
MIT
Available Tools
9 toolscheck_activityA
Read your person's agents that contributed in the last 24 hours, newest first: at most 30 agents and their five most recently touched Goals, with their latest entry headline and time. Use get_goals to read a Goal and its other contributors before starting overlapping work. Read-only; no arguments.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it declares 'Read-only; no arguments' and discloses the result shape and caps (24-hour window, newest first, ≤30 agents, 5 Goals each). It omits auth/permission needs and whether the 24h window is adjustable, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences, front-loaded with the scope and ordering, then the onward routing. Every clause adds information: window, ordering, caps, payload contents, safety, and arity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no annotations or output schema, the description must explain the return payload, and it does: agents, their Goals, latest entry headline and time, plus the cap and ordering. Only the fixed-window assumption and permissions are left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so baseline is 4. The description confirms 'no arguments', which matches the empty schema and leaves nothing for the agent to misconfigure.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb ('Read') plus a precisely scoped resource: agents that contributed in the last 24 hours, newest first, capped at 30, with their five most recent Goals and latest headline/time. It also names get_goals as the deeper-read sibling, so an agent can distinguish them without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent onward: 'Use get_goals to read a Goal and its other contributors before starting overlapping work.' That states the follow-up condition clearly, though it never says when check_activity itself is the wrong first pick (e.g., older-than-24h activity).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
configureA
Set this agent up with Paigy — call it FIRST, before contact, and any time you're unsure who you are. One call does whatever the situation needs: NOT SET UP → if this machine holds a device credential (the user ran the Paigy desktop app or harness) it hatches an identity INSTANTLY, no code and no approval; otherwise it starts the code ceremony. ALREADY SET UP → returns your current identity and the two things left to decide, renaming it or logging out. TOKEN NO LONGER VALID → says so, then re-pairs. Pass { name, voice } to choose who you are when hatching, or to RENAME yourself when already set up (pick your own; voices: rachel, george, jessica, brian, lily). Safe to call any time: idempotent, and it never writes settings — the tool-allowlist state it reports is read-only.
THE CODE CEREMONY does not open a browser; the user enters the code in the Paigy app (or scans qr). A result with { user_code, device_code, qr, user_message } has already started polling for approval in the background: you MUST immediately print the user_message (the bare code) to the user, AND in that same turn call configure again with that device_code to collect the result. It returns the moment the user approves; on { status:'pending' } call again to keep waiting; on { status:'awaiting_confirmation' } (E2EE) show the bare user_message verify code and call again to finish. The leading text block of every result states the code plainly, so it shows even if you emit no prose.
On { status:'paired' }, or whenever it returns enable_command, ALWAYS follow the enable_prompt: PRINT that command for the user to run, so Paigy's tools stop prompting each time. You cannot apply it yourself (it writes your own permission allowlist, which hosts block as privilege escalation), so print it, don't wait for it, and carry on.
LOG OUT with { logOut: true }: it logs out THIS agent only — its token is revoked server-side and its local entry removed. Other agents and this device's credential are untouched, and a later configure re-hatches instantly while the device credential exists. Disconnecting the device itself is not an agent tool.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Who you are: the name you choose when hatching, or the new one to RENAME yourself to when already set up. Pick your own — ONE or TWO words, the way you'd introduce yourself on a call (it is spoken aloud and shown in lists). 'Piper', 'Blue Heron' — never a sentence or a task description. | |
| scope | No | Which tool allowlist to report on (user or project settings). Read-only. | |
| voice | No | Your voice on calls — one of rachel, george, jessica, brian, lily. | |
| logOut | No | true: log THIS agent out — its token is revoked and its local entry removed. Other agents and this device's credential are untouched. | |
| device_code | No | Continue a code ceremony already in flight: the device_code a previous configure returned. Omit it otherwise. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden and does substantial work: idempotent, never writes settings, reported allowlist state is read-only, the code ceremony does not open a browser, and it cannot apply the enable command itself because hosts block that as privilege escalation. It also explains that pairing polls in the background and returns on approval, and that logOut revokes only this agent's token while leaving other agents and the device credential intact. However, it does not clarify failure modes (e.g., what happens if the code expires or approval is denied), so it stops short of full behavioral coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and priority ('call it FIRST'), then organized into state blocks and a code-ceremony block. It is long and capitalized heavily, and a few directives (print the bare user_message, call again to keep waiting) are restated, but for a genuinely multi-modal tool nearly every sentence carries an actionable instruction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description documents the return shapes an agent must branch on ({ user_code, device_code, qr, user_message }, { status:'pending' }, { status:'awaiting_confirmation' }, { status:'paired' }, enable_command), and explains the two-step polling interaction and the logout aftermath. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds state-dependent meaning the schema cannot: name/voice apply either when hatching or as a rename when already set up, device_code only continues an in-flight ceremony, and logOut is scoped to this agent alone. That interplay of parameters with tool state is genuine added value beyond the per-field text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Set this agent up with Paigy') and then enumerates the distinct outcomes it handles: not set up (hatch vs. code ceremony), already set up (identity + rename/logout), and invalid token (re-pair). An agent can tell instantly that this is the setup/auth entry point and not one of the sibling tools like contact or listen.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use: 'call it FIRST, before contact, and any time you're unsure who you are,' plus conditional routing for device_code continuation and logOut. It also states what to do on each returned status (pending → call again; paired/enable_command → print the enable_prompt, do not wait). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
contactA
Send to and receive from the person: completions, updates, questions, answers to questions addressed to you, withdrawals of your own questions, and what a question holds up. Every Goal you name must already exist: create it with manage_goals first; an unknown Goal is refused and nothing is sent. Every item applies on its own: read results, where a failed item names why while the rest still apply.
HOW TO ASK:
Write one question per object. Five questions are five objects in
questions, in one contact, so each can be answered on its own; one question with five parts settles nothing until all five are answered.Name the Goal you are working on as the question's
goalId: the question goes onto that Goal and its answer comes back there. It must exist: create it with manage_goals first.workItBlocksonly for work you are truly blocked on (it asks for a call); leave it out for a question you can keep working around.Never hold the process open with while-loops. A wait that comes back
expiredis not a finished conversation: wait again with contact({wait:true}) only while you have nothing else to do. While a Call you placed is open, keep receiving window after window until it ends, even when a window is empty: the person may give follow-ups or instructions. With no open Call, STOP WAITING when a window comes back with nothing new — the question stays open, and its answer reaches you on the Goal. Otherwise, yield only with a working listener or scheduled wakeup, and collect answers withcontact({wait:false})orget_goalson that wake.One question, one row. Never restate a question that is still waiting inside a new contact: keep waiting on the original, or the answer lands on one copy and the other stays open. Take back one that no longer matters with
withdrawQuestionIds.Read the Goal's conversation before asking. Never ask again what was answered or already shipped — and tell its states apart:
answeredcarries the choice inanswer, whilerepliedmeans they said something and chose none of your options, so that question is still yours to settle and their words are the line beside it.A question carries its options when you have them; a free-text question may omit them. Each option’s label must stand on its own and name its choice in full -- never
All threeorOption 2.pickMode: "many"makes the card a checklist (options they may want several of);"one", the default, a pick (one rules out the others);"rank"an ordering. Each question is sent exactly as written, with no reading in between. They can always answer in their own words, so never add an 'Other' option.A diagnosis says when, why and how it happens, then proposes one fix. Never options first.
GIVE A REPORT ITS REPLY: an update takes
replytoo, one line the person can tap instead of typing, written in THEIR voice for THAT report ("Sounds good, I'll test later") — the same care you give a question's options. What they tap is what you read back, which tells you whether they verified your work or only received it. One line, because a report has one way to close, and it may not change what happens next: a reply that would is a question. Requested delivery and completed-Goal reports require a reply (reply_required); ordinary progress may omit it.
CUT A LONG MESSAGE BEFORE YOU SEND IT: a question, an update's message or an answer is the one point, in at most 250 characters; everything else it needs goes in 'units', up to 12 {title, body} in reading order, one idea each, every title at most 50 characters and every body at most 200. The person sees the main text and the titles, and opens a unit to read its body. Over a cap is refused by name (ask_too_long, too_many_units, unit_title_too_long, unit_body_too_long) and nothing is sent.
UPDATES ask nothing, so no answer is owed and none should be awaited. An update reaches the person only when they asked you for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; any other is recorded as the Goal's progress and nobody is notified. Ordinary updates never close a Goal. On a Goal whose report card is still open, an update that reaches them is added to that card, with no new push. If the person is already on a call, anything that reaches them joins that call, with no ring.
COMPLETIONS close and report in one operation: completions:[{goalId,message,units?,reply,options?}]. The same contract works in manage_goals changes with kind:complete. message is at most 50 characters; use units when useful for initial state, changes, current state (verification and limits), and next steps / leftover work with its owner. reply is one acknowledgement in the person's voice. Optional options:[{label,hint}] suggest next steps: a tap acknowledges the report and requests that step from its author. It never reopens the completed Goal; follow-up work needs a new Goal. Closure and the report commit together or neither does. Required children and dependencies must already be finished. No Reviewer rejudges your completion; say only what your evidence supports.
RECEIVING: a contact that sends nothing returns events, a limited batch of what is addressed to you (not a history page): question, a Question you owe (answer it in answers, with its questionId); update, something new on one of your Goals (a reply, an answer: read it with get_goals); instruction, a request or note sent to you. hasMore says more are waiting. Reading acknowledges nothing: once you have handled events, confirm their eventIds with contact({ackEventIds}), and the next batch can come. contact({}) waits up to about 45 seconds for something to arrive; contact({wait:false}) returns at once. It also lists work given to you that nobody has started (assigned; your first write to it starts it) and your work gone quiet (stalled).
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Only controls when this returns. Sending: false (the default) returns at once; true waits up to about 45 seconds for a response to what you sent. Sending nothing: true (the default) waits up to about 45 seconds for anything addressed to you; false returns what is waiting now. It does not mean work is blocked, set urgency, or ask for a call. `waitOutcome` says which happened: `available`, `expired` (nothing arrived; wait again without sending again), or `not_waited`. | |
| answers | No | Answers to Questions addressed to you. | |
| updates | No | News: progress, findings, a result. An update asks nothing. It reaches the person only when they asked for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; otherwise it is recorded as the Goal's progress and nobody is notified. | |
| questions | No | Questions for the person, one per object. | |
| ackEventIds | No | The exact eventIds of the events you have handled: an acknowledgment (ACK). Reading alone acknowledges nothing, so an event comes back until you acknowledge it; after that the next batch can come. Each recipient acknowledges separately, for itself only. A Question you owe is answered (answers), never acknowledged away. | |
| completions | No | Close existing Goals and deliver their completion reports atomically. Ordinary updates never close work. | |
| withdrawQuestionIds | No | Questions you asked that no longer need an answer: you acted on them yourself, they no longer matter, or you asked wrongly. Each is cancelled, not answered: its card closes and nothing rings for it. | |
| questionDependencies | No | Add or remove what a Question you asked holds up, after asking it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations at all, the description carries the full burden and does: an unknown Goal is refused and nothing is sent, per-item failures are named in `results` while the rest still apply, over-cap messages are refused by named error and nothing sends, closure and report commit atomically or neither does, reading does not acknowledge. These are exactly the failure-mode, atomicity and delivery behaviors an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Headers and numbered rules make it front-loaded and navigable, which matters for a tool this complex, but much of the length is duplication of what the schema already documents (units caps, pickMode meanings, reply voice, waitOutcome values). Several numbered rules are procedural policy that could be tightened, so the size is defensible but not fully earned.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter tool with no output schema, the description explains the returns it needs to: `results` per-item outcomes, `events` (with `hasMore`), `waitOutcome`, and the `assigned`/`stalled` lists. It covers the full lifecycle of each operation — ask, answer, update, complete, withdraw, acknowledge — so nothing an agent must know to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds genuine meaning on top: the one-question-per-object rule, the demand that option labels stand on their own ("never 'All three' or 'Option 2'"), never adding an 'Other' option, and the requirement that a report's `reply` be written in the person's voice. The `wait`/`waitOutcome` and `userExplicitlyRequested` semantics are also restated with interpretation rather than merely repeated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb pair and resource (send to / receive from the person) and enumerates the message kinds it carries — questions, answers, updates, completions, withdrawals. It distinguishes itself from manage_goals explicitly ("Every Goal you name must already exist: create it with manage_goals first"), but draws no line against the receive-side siblings like listen or get_goals, which an agent could reasonably confuse with its `events` mode.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description goes well beyond context: it prescribes when to use questions vs updates vs completions, when to set workItBlocks ("only for work you are truly blocked on"), when to keep waiting vs stop waiting, and when to use completions vs manage_goals with kind:complete. It also states explicit exclusions ("Never restate a question that is still waiting", "Never set it to make a message louder"), which is the top of the scale.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_deliveryA
Read a Delivery in full: its whole ask, units, options and answers, plus current callState and callOutcome for a Call. Any agent of the same account may read it; another account is not disclosed. Reading never acknowledges or resends anything. Use this after a call or when receive names a Call you are waiting on.
| Name | Required | Description | Default |
|---|---|---|---|
| deliveryId | Yes | The Delivery id returned by contact or receive. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses access scope (same-account agents may read; other accounts are not disclosed) and explicitly guarantees no side effects ("Reading never acknowledges or resends anything"). It omits failure/not-found behavior and any statement about the meaning or variability of callState/callOutcome values.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tightly packed sentences: return content first, then access/side-effect guarantees, then the usage trigger. Every clause adds information, though "its whole ask, units, options and answers" is slightly list-heavy in a way that only pays off if those nouns are familiar.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly compensates by enumerating the returned content. The one-parameter schema is fully covered by the schema itself. What a reader still cannot infer is how to interpret callState/callOutcome values, a minor gap for a read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter and schema coverage is 100%; the schema already documents deliveryId including its origin ("returned by contact or receive"). The description adds no format, constraint, or sourcing detail beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb ("Read") and resource ("Delivery") and enumerates what comes back: the ask, units, options, answers, plus callState and callOutcome. It does not explicitly differentiate itself from the listed siblings (contact, receive, search, listen), though it references contact/receive as the producers of the id.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states a clear trigger: "Use this after a call or when receive names a Call you are waiting on." That is concrete timing guidance. It does not name a competing read tool or state when not to use it, so it stops short of full alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_goalsA
Read one to ten Goals by goalIds, returned in the same order under goals (a read never puts you on them). history applies to every requested Goal. A refused read fails the call with its original refusal; no partial result is presented as complete. Each Goal includes its ten most recent other contributors (names, latest entry headlines and times), outcome, state, revision, progress, blockers, the conversation on it (each question with its options and what was decided), next, the one step to take, and more, where to read further. A question in that conversation reads open (nothing yet), answered (a choice was made, and answer carries it), replied (they said something and the read settled the question on their words — NO option of yours was chosen, and the words are the reply line beside it, so read that before you act), or closed. The conversation carries everything the person said, every open question and your newest entry; your older entries are left out and counted — history: true reads every entry in full. Every Goal of your person is readable, whichever of their agents owns it; another account's Goals are not disclosed.
| Name | Required | Description | Default |
|---|---|---|---|
| goalIds | Yes | The Goals to read, in order; one to ten IDs. | |
| history | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: a refused read fails the whole call atomically ('no partial result is presented as complete'), results preserve request order, cross-account Goals are not disclosed, and history changes how much of the conversation is returned. These are exactly the behavioral facts an agent cannot get from schema or annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Everything is packed into a single monolithic paragraph, and the conversation return value is explained twice (once as 'the conversation on it (each question with its options and what was decided)' and again in the open/answered/replied/closed detail). Some phrasing is opaque ('a read never puts you on them'). Content mostly earns its place, but structure and redundancy cost points.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must describe the return shape — and it does thoroughly: goals array, contributors, outcome, state, revision, progress, blockers, conversation questions with options and answers, next, and more. With no annotations and a read-only profile, nothing an agent needs to invoke or interpret this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50%: goalIds is described in the schema, but history has no schema description. The prose compensates for that gap by explaining history's semantics ('applies to every requested Goal', 'history: true reads every entry in full') and adds ordering behavior for goalIds. Adds genuine meaning beyond the schema for the undocumented parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Front-loads a specific verb+resource+cardinality: 'Read one to ten Goals by goalIds, returned in the same order under goals.' An agent immediately knows this is the batch-read-by-ID operation. It does not name or contrast itself with the sibling manage_goals, so sibling differentiation is left implicit rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real scope/boundary guidance: 'Every Goal of your person is readable, whichever of their agents owns it; another account's Goals are not disclosed.' That tells the agent what will and will not resolve, and the history note clarifies a usage condition. It never states when to prefer this over siblings like manage_goals or search, so no explicit alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listenA
Am I listening for answers, and can Paigy resume this session? Takes no arguments. Returns status listening for harness delivery or a running listener with a ready wake adapter; receiving means a process is running but automatic resume is not confirmed (read its wake error or watch its output); unpaired means call configure; start gives the exact command to run NOW as a watched background task for this session. Start it once. Codex queues into CODEX_THREAD_ID automatically when its CLI supports queue; PAIGY_ON_WAKE overrides it. A successful queue is not evidence the agent handled the answer: receive with contact({ wait: false }) and read the relevant Goal, then respond with contact. This tool never subscribes or starts anything itself.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so well: it enumerates the return statuses (listening/receiving/unpaired/start), clarifies that a running process does not guarantee resume, notes PAIGY_ON_WAKE overrides, and explicitly states 'This tool never subscribes or starts anything itself' and that a successful queue is not proof of handling. This is substantive context an agent needs before invoking.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The content is dense and largely earns its place, but it is not front-loaded: it opens with a question and strings multiple loosely-related clauses (status definitions, queue behavior, receive workflow, override env var) into long run-ons. A reader must parse several sentences before reaching the actionable 'call configure' / 'start once' guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description appropriately documents the meaning of each returned status and the follow-up workflow, which is the key missing structured data. It assumes knowledge of domain terms (Paigy, wake adapter) without defining them, and omits how the 'start' command relates to configure, leaving a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so baseline is 4. The description confirms 'Takes no arguments,' which is redundant with the empty schema but harmless and removes any doubt.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening question states the resource (listening for answers / resume readiness) and the tool's role as a status probe, and it explicitly disambiguates from siblings by routing unpaired states to configure. However, the framing as a rhetorical question plus the dense jargon (Paigy, wake adapter, CODEX_THREAD_ID) makes the core verb ('check status') less immediately obvious than a direct statement would.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete condition-action mappings: 'unpaired' means call configure, and it warns 'Start it once' plus describes the correct receive path via contact({ wait: false }). It names alternatives (configure, contact) but does not compare against check_activity or other status-oriented siblings, so routing is clear only for specific states.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manage_goalsA
Create, edit, assign, organize or close work. Every change here changes Goals; answering, withdrawing or asking Questions stays in contact. Each change applies independently: a refused one names why (results[i].error, e.g. goal_revision_conflict, goal_children_open, goal_not_found) and the rest still apply, so read every result: a partial result is never a complete success. Kinds: complete (goalId, message capped at 50 characters, units, reply, optional next-step options {label, hint}) closes and reports atomically, exactly as contact.completions; create (title, outcome, ownerId, parentGoalId, sourceEntryIds) returns the new Goal's id in results[i].goalId, in the order requested, to use in later calls (an outcome is one paragraph, at most 500 characters: split more into child Goals with parentGoalId); edit (title and/or outcome); state (open, completed, canceled); assign (ownerId); defer (until: the Goal waits until then and its owner is woken when it passes; null takes it back); move (parentGoalId, or null for a root: only this Goal moves); dependency (add or remove: goalId waits on dependsOnGoalId to start or to complete). A Goal cannot be completed while its required children or dependencies remain open: finish or move them first. Finishing the children does not prove the parent's own work is done. An edit applies at the version you last read: if someone changed the Goal since, it is refused as goal_revision_conflict, so read it again (get_goals) and reconsider. You may change any Goal of your person; a change puts you on it. Returns ok (every change applied), results per change (applied or failed), and goals, each changed Goal's id, state, title, outcome and revision.
| Name | Required | Description | Default |
|---|---|---|---|
| changes | Yes | The changes, applied in order, each on its own. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so richly: atomic completion, independent application of each change, partial-result semantics, named error codes, child/dependency completion constraints, revision-conflict behavior, defer wake-up behavior, and the return shape are all disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and organized by concern, and its length is largely justified by eight distinct change kinds with no annotations. It is still dense and repeats some constraints already present in the schema, so it is not maximally concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, but the description fully specifies the return structure: ok, per-change results, and changed goals with id, state, title, outcome, and revision. It also covers mutation constraints and error behavior, so an agent has enough context to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds cross-parameter meaning beyond the schema: completion is refused while required children or dependencies remain open, edits apply only at the last-read revision, dependency changes distinguish start versus complete, and created Goal IDs are returned in request order.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with specific verbs and a clear resource: 'Create, edit, assign, organize or close work' and 'Every change here changes Goals.' It explicitly distinguishes this from the sibling contact by stating that answering, withdrawing, or asking Questions stays in contact.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly routes non-Goal activity to contact and tells the agent to read again with get_goals after a conflict. It also explains when each change kind applies and warns that independent changes require reading every result, leaving little ambiguity about how to choose this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchA
Search your person's history across all of their agents: Entries (what anyone said or wrote, typed or spoken on a call), Goals (by title and outcome) and replies -- the person's answers, acknowledgements and deferrals (type answer; found by their summary, by the question or report they reply to, or by the words that gave them). query is words to look for; records sharing more of its words rank first, and exact names work. types narrows it to entry, goal and/or answer (default: all three). goalId searches under one Goal: its Entries, the replies to its items, and it and its immediate children. limit is matches per type, 1 to 20 (default 8). Read-only. Each match carries its whole saved words, its ID and its links (a reply carries its kind -- answered, acknowledged or deferred -- whether it is closed (a deferral is not), its summary in under ten words, its question or report, the choice made and the Entries that support it); omitted counts what matched but was left out, so narrow the words or add a goalId to see it. Nothing found is not proof that nothing exists; a refused search says why. Sealed (encrypted) content is never searched or returned.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| types | No | ||
| goalId | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the burden itself and does so: it declares "Read-only", explains that refusals come with a reason, that "Nothing found is not proof that nothing exists", and that sealed (encrypted) content is never searched or returned. It omits permission/auth requirements, but the safety and failure semantics are unusually well disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and read-only status are front-loaded, but the body is one dense paragraph of stacked parentheticals (the reply-links enumeration in particular) that is hard to scan. It is informative but bloated; several nested clauses could be split or trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must explain returns, and it does thoroughly: each match's saved words, ID, links, reply kind, closed state, under-ten-word summary, question/report, choice and supporting Entries, plus the `omitted` count. An agent has everything needed to call and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, yet the prose defines all four parameters meaningfully: query ranking by shared words and exact names, types' three values and default, goalId's scope (a Goal's Entries, replies to its items, itself and immediate children), and limit's unit and 1-20 range with default 8. It adds semantics well beyond the raw schema types.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening clause gives a specific verb and resource ("Search your person's history across all of their agents") and then enumerates the searched corpora: Entries, Goals and replies. That is far more precise than the bare name "search", though it never names a sibling (get_goals, check_activity, listen) to disambiguate the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives real refinement guidance ("narrow the words or add a goalId to see it", default types of all three) but never states when to reach for this tool versus get_goals or check_activity. Usage is implied through parameter behavior rather than an explicit when/when-not rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_feedbackA
Send feedback about Paigy itself (a bug report, an idea) straight to the Paigy team. Send it only when the person asked you to, or agreed when you offered: it goes to Paigy, never to the person, and nobody answers it here. Not for your work or a question for the person: use contact for those. Returns whether it was stored.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | bug: something Paigy does wrong. idea: something it should do. other: anything else. | other |
| text | Yes | The report, in markdown: what happened, what was expected, how to reproduce it, versions, evidence. At most 50000 characters. | |
| title | No | One line naming it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose key behavior: the message goes to Paigy and never to the person, nobody answers here, and it returns whether it was stored. It does not cover permissions or rate limits, a minor gap but not a contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Compact and front-loaded: the core action comes first, then the guidance and the routing constraint. It is dense but every clause earns its place; only slight tightening would improve it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-param, one-required tool with no output schema, the description covers purpose, recipient routing, side effects (no reply), the return value, and the alternative tool. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents kind, text, and title with examples and constraints. The description adds no parameter-level detail, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Send feedback about Paigy itself') and clarifies the destination scope ('straight to the Paigy team'). It explicitly distinguishes itself from the sibling 'contact' tool, so an agent can route correctly without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use condition ('only when the person asked you to, or agreed when you offered') and a when-not with the named alternative ('Not for your work or a question for the person: use contact for those'). Routing is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v1.0.13- Changed
contact7 fields changed- added
Input schema / properties / completionsAdded value: +{ + "description": "Close existing Goals and deliver their completion reports atomically. Ordinary updates never close work.", + "items": { + "additionalProperties": false, + "properties": { + "goalId": { + "description": "The existing Goal to complete.", + "format": "uuid", + "type": "string" + }, + "message": { + "description": "Completion headline, at most 50 characters.", + "maxLength": 50, + "minLength": 1, + "type": "string" + }, + "options": { + "description": "Optional next steps the person may initiate: label (50 characters) and consequence in hint (200). Selecting one acknowledges the report and requests that step from its author; it never reopens this Goal.", + "items": { + "additionalProperties": false, + "properties": { + "hint": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "label": { + "maxLength": 50, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "label", + "hint" + ], + "type": "object" + }, + "maxItems": 5, + "type": "array" + }, + "reply": { + "description": "One acknowledgement in the person's voice, at most 50 characters. Acknowledgement alone requests no follow-up and does not claim they tested the work.", + "maxLength": 50, + "minLength": 1, + "type": "string" + }, + "units": { + "description": "Suggest initial state, changes, current state with verification and limits, and next steps / leftover work with its owner when useful. One idea per unit; omit unnecessary sections.", + "items": { + "additionalProperties": false, + "properties": { + "body": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "title": { + "maxLength": 50, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "title", + "body" + ], + "type": "object" + }, + "maxItems": 12, + "type": "array" + } + }, + "required": [ + "goalId", + "message", + "reply" + ], + "type": "object" + }, + "maxItems": 20, + "minItems": 1, + "type": "array" +} - changed
Input schema / properties / questions / items / properties / options / descriptionPrevious value: -"The choices, when you have them. Each label stands on its own."New value: +"The choices, when you have them. Each label stands on its own, at most 50 characters; a hint, at most 200." - changed
Input schema / properties / questions / items / properties / options / items / properties / hint / descriptionPrevious value: -"Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main')."New value: +"Optional: what choosing it does, at most 200 characters (e.g. 'Reruns test suite', 'Merges to main')." - changed
Input schema / properties / questions / items / properties / options / items / properties / hint / maxLengthPrevious value: -500New value: +200 - added
Input schema / properties / questions / items / properties / options / items / properties / label / descriptionAdded value: +"The choice, at most 50 characters, standing on its own." - changed
Input schema / properties / questions / items / properties / options / items / properties / label / maxLengthPrevious value: -1000New value: +50 - added
Input schema / properties / updates / items / properties / replyAdded value: +{ + "description": "What this report's button says instead of \"Got it\", at most 50 characters, written in THEIR voice for THIS report (\"Sounds good, I'll test later\") -- the care you give a question's options, so what they tap tells you whether they verified your work or only received it. One tap sends exactly these words back to you. Words that would CHANGE what happens next are a question, not a reply to a report: it still asks nothing and still owes you no answer. The reply is required for requested delivery and completed Goals; ordinary progress may omit it.", + "minLength": 1, + "type": "string" +}
- Added
get_delivery - Removed
get_goal - Added
get_goals - Changed
manage_goals1 field changed- changed
Input schema / properties / changes / items / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "kind": { - "const": "create", - "type": "string" - }, - "outcome": { - "description": "The full desired result. There is no third description field.", - "maxLength": 10000, - "minLength": 1, - "type": "string" - }, - "ownerId": { - "description": "Who owns the work: an agent's participant (as check_activity shows it) or the person's. Omitted: you.", - "minLength": 1, - "type": "string" - }, - "parentGoalId": { - "description": "The Goal it belongs under. Omitted: a root.", - "format": "uuid", - "type": "string" - }, - "sourceEntryIds": { - "description": "The whole Entries the work came from, ones you can read.", - "items": { - "format": "uuid", - "type": "string" - }, - "maxItems": 20, - "type": "array" - }, - "title": { - "description": "The Goal's short display name: one to five words, how a person refers to it out loud.", - "maxLength": 80, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "title", - "outcome" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "goalId": { - "description": "The Goal to change, as a read shows it.", - "format": "uuid", - "type": "string" - }, - "kind": { - "const": "edit", - "type": "string" - }, - "outcome": { - "description": "The full desired result. There is no third description field.", - "maxLength": 10000, - "minLength": 1, - "type": "string" - }, - "title": { - "description": "The Goal's short display name: one to five words, how a person refers to it out loud.", - "maxLength": 80, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "goalId" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "goalId": { - "description": "The Goal to change, as a read shows it.", - "format": "uuid", - "type": "string" - }, - "kind": { - "const": "state", - "type": "string" - }, - "state": { - "description": "completed: the Goal's own work is done now (refused while required children are open); open: reopen it; canceled: it will not be done.", - "enum": [ - "open", - "completed", - "canceled" - ], - "type": "string" - } - }, - "required": [ - "kind", - "goalId", - "state" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "goalId": { - "description": "The Goal to change, as a read shows it.", - "format": "uuid", - "type": "string" - }, - "kind": { - "const": "assign", - "type": "string" - }, - "ownerId": { - "description": "The new owner's participant.", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "goalId", - "ownerId" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "goalId": { - "description": "The Goal to change, as a read shows it.", - "format": "uuid", - "type": "string" - }, - "kind": { - "const": "defer", - "type": "string" - }, - "until": { - "anyOf": [ - { - "format": "date-time", - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Postpone it until this instant: it waits until then, and its owner is woken when it passes (a promise to follow up later). null takes the postponement back." - } - }, - "required": [ - "kind", - "goalId", - "until" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "goalId": { - "description": "The Goal to change, as a read shows it.", - "format": "uuid", - "type": "string" - }, - "kind": { - "const": "move", - "type": "string" - }, - "parentGoalId": { - "anyOf": [ - { - "format": "uuid", - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Its new parent, or null for a root. Only this Goal moves; its new parent's other children stay." - } - }, - "required": [ - "kind", - "goalId", - "parentGoalId" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "action": { - "description": "What waits: starting goalId, or completing it.", - "enum": [ - "start", - "complete" - ], - "type": "string" - }, - "change": { - "enum": [ - "add", - "remove" - ], - "type": "string" - }, - "dependsOnGoalId": { - "description": "The Goal it waits on.", - "format": "uuid", - "type": "string" - }, - "goalId": { - "description": "The Goal to change, as a read shows it.", - "format": "uuid", - "type": "string" - }, - "kind": { - "const": "dependency", - "type": "string" - }, - "reason": { - "description": "Why, as an explanation, never as policy.", - "maxLength": 2000, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "kind", - "change", - "goalId", - "dependsOnGoalId", - "action" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "kind": { + "const": "create", + "type": "string" + }, + "outcome": { + "description": "The desired result, one paragraph of at most 500 characters. More than that is more work: create child Goals under it (parentGoalId). There is no third description field.", + "maxLength": 500, + "minLength": 1, + "type": "string" + }, + "ownerId": { + "description": "Who owns the work: an agent's participant (as check_activity shows it) or the person's. Omitted: you.", + "minLength": 1, + "type": "string" + }, + "parentGoalId": { + "description": "The Goal it belongs under. Omitted: a root.", + "format": "uuid", + "type": "string" + }, + "sourceEntryIds": { + "description": "The whole Entries the work came from, ones you can read.", + "items": { + "format": "uuid", + "type": "string" + }, + "maxItems": 20, + "type": "array" + }, + "title": { + "description": "The Goal's short display name: one to five words, how a person refers to it out loud.", + "maxLength": 80, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "title", + "outcome" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "goalId": { + "description": "The existing Goal to complete.", + "format": "uuid", + "type": "string" + }, + "kind": { + "const": "complete", + "type": "string" + }, + "message": { + "description": "Completion headline, at most 50 characters.", + "maxLength": 50, + "minLength": 1, + "type": "string" + }, + "options": { + "description": "Optional next steps the person may initiate: label (50 characters) and consequence in hint (200). Selecting one acknowledges the report and requests that step from its author; it never reopens this Goal.", + "items": { + "additionalProperties": false, + "properties": { + "hint": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "label": { + "maxLength": 50, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "label", + "hint" + ], + "type": "object" + }, + "maxItems": 5, + "type": "array" + }, + "reply": { + "description": "One acknowledgement in the person's voice, at most 50 characters. Acknowledgement alone requests no follow-up and does not claim they tested the work.", + "maxLength": 50, + "minLength": 1, + "type": "string" + }, + "units": { + "description": "Suggest initial state, changes, current state with verification and limits, and next steps / leftover work with its owner when useful. One idea per unit; omit unnecessary sections.", + "items": { + "additionalProperties": false, + "properties": { + "body": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "title": { + "maxLength": 50, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "title", + "body" + ], + "type": "object" + }, + "maxItems": 12, + "type": "array" + } + }, + "required": [ + "goalId", + "message", + "reply", + "kind" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "goalId": { + "description": "The Goal to change, as a read shows it.", + "format": "uuid", + "type": "string" + }, + "kind": { + "const": "edit", + "type": "string" + }, + "outcome": { + "description": "The desired result, one paragraph of at most 500 characters. More than that is more work: create child Goals under it (parentGoalId). There is no third description field.", + "maxLength": 500, + "minLength": 1, + "type": "string" + }, + "title": { + "description": "The Goal's short display name: one to five words, how a person refers to it out loud.", + "maxLength": 80, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "goalId" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "goalId": { + "description": "The Goal to change, as a read shows it.", + "format": "uuid", + "type": "string" + }, + "kind": { + "const": "state", + "type": "string" + }, + "state": { + "description": "completed: the Goal's own work is done now (refused while required children are open); open: reopen it; canceled: it will not be done.", + "enum": [ + "open", + "completed", + "canceled" + ], + "type": "string" + } + }, + "required": [ + "kind", + "goalId", + "state" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "goalId": { + "description": "The Goal to change, as a read shows it.", + "format": "uuid", + "type": "string" + }, + "kind": { + "const": "assign", + "type": "string" + }, + "ownerId": { + "description": "The new owner's participant.", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "goalId", + "ownerId" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "goalId": { + "description": "The Goal to change, as a read shows it.", + "format": "uuid", + "type": "string" + }, + "kind": { + "const": "defer", + "type": "string" + }, + "until": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Postpone it until this instant: it waits until then, and its owner is woken when it passes (a promise to follow up later). null takes the postponement back." + } + }, + "required": [ + "kind", + "goalId", + "until" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "goalId": { + "description": "The Goal to change, as a read shows it.", + "format": "uuid", + "type": "string" + }, + "kind": { + "const": "move", + "type": "string" + }, + "parentGoalId": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Its new parent, or null for a root. Only this Goal moves; its new parent's other children stay." + } + }, + "required": [ + "kind", + "goalId", + "parentGoalId" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "action": { + "description": "What waits: starting goalId, or completing it.", + "enum": [ + "start", + "complete" + ], + "type": "string" + }, + "change": { + "enum": [ + "add", + "remove" + ], + "type": "string" + }, + "dependsOnGoalId": { + "description": "The Goal it waits on.", + "format": "uuid", + "type": "string" + }, + "goalId": { + "description": "The Goal to change, as a read shows it.", + "format": "uuid", + "type": "string" + }, + "kind": { + "const": "dependency", + "type": "string" + }, + "reason": { + "description": "Why, at most 250 characters, as an explanation, never as policy.", + "maxLength": 250, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "kind", + "change", + "goalId", + "dependsOnGoalId", + "action" + ], + "type": "object" + } +]
13 tool updates
v1.0.12- Added
check_activity - Removed
check_replies - Removed
claim_goal - Added
configure - Changed
contact3 fields changed- added
Input schema / additionalPropertiesAdded value: +false - removed
Input schema / anyOfRemoved value: -[ - { - "additionalProperties": false, - "properties": { - "asks": { - "description": "The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy.", - "items": { - "additionalProperties": false, - "properties": { - "answers": { - "description": "Your reply answers a question the person asked you: the id the conversation shows for it (8 characters or whole). Their question closes with this reply as its answer, and any decision of yours it was holding back goes back to them. Needs parentId: the Goal the question is on. The reply is sent to them as it is; to also ask something new, send that as its own ask.", - "pattern": "^[0-9a-fA-F-]{8,36}$", - "type": "string" - }, - "ask": { - "description": "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy reads every ask once and takes a bundled one apart into its own cards anyway — each question a Question on the one Goal the ask lands on, never a Goal of its own — but the words it splits are its reading, not yours. News, progress and findings are their own contact; ANY contact for a person already on a call JOINS that call, whatever channel you asked for, so several arrive as one call.", - "maxLength": 10000, - "minLength": 1, - "type": "string" - }, - "id": { - "description": "Optional idempotency key or client-side ID for this specific ask.", - "type": "string" - }, - "options": { - "items": { - "additionalProperties": false, - "properties": { - "hint": { - "description": "Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').", - "maxLength": 500, - "type": "string" - }, - "html": { - "description": "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images — inline CSS and data: URIs only; <=16KB. Rendered edge-to-edge in a responsive card that is 200pt tall (about 320pt wide on a phone, with the next option peeking beside it); make your HTML fit that viewport. Use for layout/CSS mockups, tables, diffs. For a hosted image use `image` instead.", - "maxLength": 16384, - "type": "string" - }, - "image": { - "description": "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use `html` instead.", - "format": "uri", - "type": "string" - }, - "label": { - "maxLength": 1000, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "label" - ], - "type": "object" - }, - "maxItems": 6, - "minItems": 1, - "type": "array" - }, - "parentId": { - "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", - "format": "uuid", - "type": "string" - }, - "repo": { - "description": "Optional repository context.", - "type": "string" - }, - "select": { - "description": "How the options are answered: \"one\" (default) to pick one, \"many\" to tick any number of them. Use \"many\" when the options are independent things they may want several of — never combinations of them like \"all three\" or \"1 and 3\". Ignored without options.", - "enum": [ - "one", - "many" - ], - "type": "string" - } - }, - "required": [ - "ask" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, - "channel": { - "default": "notification", - "enum": [ - "notification", - "call" - ], - "type": "string" - }, - "waiting": { - "default": "none", - "description": "hard requests a call even when channel is notification; user permissions and ring cooldowns still apply.", - "enum": [ - "none", - "hard" - ], - "type": "string" - } - }, - "required": [ - "asks" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "deliveryId": { - "format": "uuid", - "type": "string" - } - }, - "required": [ - "deliveryId" - ], - "type": "object" - } -] - added
Input schema / propertiesAdded value: +{ + "ackEventIds": { + "description": "The exact eventIds of the events you have handled: an acknowledgment (ACK). Reading alone acknowledges nothing, so an event comes back until you acknowledge it; after that the next batch can come. Each recipient acknowledges separately, for itself only. A Question you owe is answered (answers), never acknowledged away.", + "items": { + "format": "uuid", + "type": "string" + }, + "maxItems": 100, + "minItems": 1, + "type": "array" + }, + "answers": { + "description": "Answers to Questions addressed to you.", + "items": { + "additionalProperties": false, + "properties": { + "answer": { + "additionalProperties": false, + "properties": { + "selectedOptionIds": { + "description": "The ids of the options you choose, when the Question offered options (in order, for a ranking).", + "items": { + "minLength": 1, + "type": "string" + }, + "maxItems": 6, + "minItems": 1, + "type": "array" + }, + "text": { + "description": "Your answer in your own words, at most 250 characters; the context goes in units.", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "questionId": { + "description": "The Question you answer: its id as the event or the conversation shows it (8 characters or whole).", + "pattern": "^[0-9a-fA-F-]{8,36}$", + "type": "string" + }, + "units": { + "description": "The context this message needs, as up to 12 units in reading order, each {title, body}: a title of at most 50 characters and a body of at most 200. One idea per unit. Leave it out when the main text says it all.", + "items": { + "additionalProperties": false, + "properties": { + "body": { + "description": "The unit itself, at most 200 characters.", + "minLength": 1, + "type": "string" + }, + "title": { + "description": "What this unit is about, at most 50 characters. The app lists the titles; the person taps one to read its body.", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "title", + "body" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "questionId", + "answer" + ], + "type": "object" + }, + "maxItems": 20, + "minItems": 1, + "type": "array" + }, + "questionDependencies": { + "description": "Add or remove what a Question you asked holds up, after asking it.", + "items": { + "additionalProperties": false, + "properties": { + "action": { + "description": "What waits: starting or completing a Goal, or answering a Question.", + "enum": [ + "start", + "complete", + "answer" + ], + "type": "string" + }, + "blocked": { + "additionalProperties": false, + "description": "A Goal or a Question, by its id.", + "properties": { + "id": { + "format": "uuid", + "type": "string" + }, + "type": { + "enum": [ + "goal", + "question" + ], + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "change": { + "enum": [ + "add", + "remove" + ], + "type": "string" + }, + "questionId": { + "description": "A Question you asked.", + "pattern": "^[0-9a-fA-F-]{8,36}$", + "type": "string" + }, + "reason": { + "description": "Why, as an explanation, never as policy.", + "maxLength": 500, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "questionId", + "change", + "blocked", + "action" + ], + "type": "object" + }, + "maxItems": 20, + "minItems": 1, + "type": "array" + }, + "questions": { + "description": "Questions for the person, one per object.", + "items": { + "additionalProperties": false, + "properties": { + "goalId": { + "description": "The Goal the question is about, which must exist (create it with manage_goals first). Its answer comes back there.", + "format": "uuid", + "type": "string" + }, + "options": { + "description": "The choices, when you have them. Each label stands on its own.", + "items": { + "additionalProperties": false, + "properties": { + "hint": { + "description": "Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').", + "maxLength": 500, + "type": "string" + }, + "htmlPreview": { + "description": "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images — inline CSS and data: URIs only; <=16KB. Rendered edge-to-edge in a responsive card that is 200pt tall (about 320pt wide on a phone, with the next option peeking beside it); make your HTML fit that viewport. Use for layout/CSS mockups, tables, diffs. For a hosted image use the image URL instead.", + "maxLength": 16384, + "type": "string" + }, + "id": { + "description": "Optional: this option's own id, which answers name it by (selectedOptionIds). Give every option one, or none: without them the options are numbered \"1\", \"2\", … in order.", + "maxLength": 64, + "minLength": 1, + "pattern": "^[A-Za-z0-9_.:-]+$", + "type": "string" + }, + "imgUrl": { + "description": "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use the HTML preview instead.", + "format": "uri", + "type": "string" + }, + "label": { + "maxLength": 1000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "label" + ], + "type": "object" + }, + "maxItems": 6, + "minItems": 1, + "type": "array" + }, + "pickMode": { + "description": "How the options are answered: \"one\" (the default) a pick, for alternatives; \"many\" a checklist, for independent options they may want several of; \"rank\" an order of all of them. Only with options.", + "enum": [ + "one", + "many", + "rank" + ], + "type": "string" + }, + "question": { + "description": "ONE question, in at most 250 characters, and only what is needed to answer it; the context goes in units. Several questions are several objects, one each: an answer settles the one question it was given, so a person who answers the part of a bundled question that interested them settles nothing and is asked again. Separate questions cost nothing: ANY contact for a person already on a call JOINS that call, so several arrive as one call.", + "minLength": 1, + "type": "string" + }, + "questionId": { + "description": "Optional: your own stable id for this question (a UUID), so a resend is the same question. Minted for you when omitted; the result returns it.", + "format": "uuid", + "type": "string" + }, + "units": { + "description": "The context this message needs, as up to 12 units in reading order, each {title, body}: a title of at most 50 characters and a body of at most 200. One idea per unit. Leave it out when the main text says it all.", + "items": { + "additionalProperties": false, + "properties": { + "body": { + "description": "The unit itself, at most 200 characters.", + "minLength": 1, + "type": "string" + }, + "title": { + "description": "What this unit is about, at most 50 characters. The app lists the titles; the person taps one to read its body.", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "title", + "body" + ], + "type": "object" + }, + "type": "array" + }, + "userExplicitlyRequested": { + "description": "Only what the person said about THIS message, in so many words: \"any\" when they asked you to send it to them (\"send it to my phone\", \"message me the result\"), \"call\" when they asked to be called about it. It is then delivered (a call rings for the whole contact, and carries everything waiting on them); omitted, an update is only recorded as the Goal's progress unless the person needs it. Never set it to make a message louder.", + "enum": [ + "any", + "call" + ], + "type": "string" + }, + "workItBlocks": { + "description": "The work that cannot go on until this is answered: a Goal's start or completion, or another Question's answer. Only for work truly blocked; it asks for a call. Leave it out for a question you can keep working around.", + "items": { + "additionalProperties": false, + "properties": { + "action": { + "description": "What waits: starting or completing a Goal, or answering a Question.", + "enum": [ + "start", + "complete", + "answer" + ], + "type": "string" + }, + "blocked": { + "additionalProperties": false, + "description": "A Goal or a Question, by its id.", + "properties": { + "id": { + "format": "uuid", + "type": "string" + }, + "type": { + "enum": [ + "goal", + "question" + ], + "type": "string" + } + }, + "required": [ + "type", + "id" + ], + "type": "object" + }, + "reason": { + "description": "Why, as an explanation, never as policy.", + "maxLength": 500, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "blocked", + "action" + ], + "type": "object" + }, + "maxItems": 10, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "question", + "goalId" + ], + "type": "object" + }, + "maxItems": 20, + "minItems": 1, + "type": "array" + }, + "updates": { + "description": "News: progress, findings, a result. An update asks nothing. It reaches the person only when they asked for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; otherwise it is recorded as the Goal's progress and nobody is notified.", + "items": { + "additionalProperties": false, + "properties": { + "goalIds": { + "description": "The Goals it is about, each one that exists: the one it is mainly about first.", + "items": { + "format": "uuid", + "type": "string" + }, + "maxItems": 10, + "minItems": 1, + "type": "array" + }, + "message": { + "description": "The one point, at most 250 characters; the context goes in units.", + "minLength": 1, + "type": "string" + }, + "units": { + "description": "The context this message needs, as up to 12 units in reading order, each {title, body}: a title of at most 50 characters and a body of at most 200. One idea per unit. Leave it out when the main text says it all.", + "items": { + "additionalProperties": false, + "properties": { + "body": { + "description": "The unit itself, at most 200 characters.", + "minLength": 1, + "type": "string" + }, + "title": { + "description": "What this unit is about, at most 50 characters. The app lists the titles; the person taps one to read its body.", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "title", + "body" + ], + "type": "object" + }, + "type": "array" + }, + "userExplicitlyRequested": { + "description": "Only what the person said about THIS message, in so many words: \"any\" when they asked you to send it to them (\"send it to my phone\", \"message me the result\"), \"call\" when they asked to be called about it. It is then delivered (a call rings for the whole contact, and carries everything waiting on them); omitted, an update is only recorded as the Goal's progress unless the person needs it. Never set it to make a message louder.", + "enum": [ + "any", + "call" + ], + "type": "string" + } + }, + "required": [ + "message", + "goalIds" + ], + "type": "object" + }, + "maxItems": 20, + "minItems": 1, + "type": "array" + }, + "wait": { + "description": "Only controls when this returns. Sending: false (the default) returns at once; true waits up to about 45 seconds for a response to what you sent. Sending nothing: true (the default) waits up to about 45 seconds for anything addressed to you; false returns what is waiting now. It does not mean work is blocked, set urgency, or ask for a call. `waitOutcome` says which happened: `available`, `expired` (nothing arrived; wait again without sending again), or `not_waited`.", + "type": "boolean" + }, + "withdrawQuestionIds": { + "description": "Questions you asked that no longer need an answer: you acted on them yourself, they no longer matter, or you asked wrongly. Each is cancelled, not answered: its card closes and nothing rings for it.", + "items": { + "pattern": "^[0-9a-fA-F-]{8,36}$", + "type": "string" + }, + "maxItems": 10, + "minItems": 1, + "type": "array" + } +}
- Removed
create_goal - Added
manage_goals - Removed
onboard - Removed
pair - Added
search - Added
send_feedback - Removed
unpair - Removed
update_goal
1 tool update
v1.0.11- Changed
contact1 field changed- changed
Input schema / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "asks": { - "description": "The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy.", - "items": { - "additionalProperties": false, - "properties": { - "ask": { - "description": "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy reads every ask once and takes a bundled one apart into its own cards anyway — each question a Question on the one Goal the ask lands on, never a Goal of its own — but the words it splits are its reading, not yours. News, progress and findings are their own contact; ANY contact for a person already on a call JOINS that call, whatever channel you asked for, so several arrive as one call.", - "maxLength": 10000, - "minLength": 1, - "type": "string" - }, - "id": { - "description": "Optional idempotency key or client-side ID for this specific ask.", - "type": "string" - }, - "options": { - "items": { - "additionalProperties": false, - "properties": { - "hint": { - "description": "Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').", - "maxLength": 500, - "type": "string" - }, - "html": { - "description": "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images — inline CSS and data: URIs only; <=16KB. Rendered edge-to-edge in a responsive card that is 200pt tall (about 320pt wide on a phone, with the next option peeking beside it); make your HTML fit that viewport. Use for layout/CSS mockups, tables, diffs. For a hosted image use `image` instead.", - "maxLength": 16384, - "type": "string" - }, - "image": { - "description": "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use `html` instead.", - "format": "uri", - "type": "string" - }, - "label": { - "maxLength": 1000, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "label" - ], - "type": "object" - }, - "maxItems": 6, - "minItems": 1, - "type": "array" - }, - "parentId": { - "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", - "format": "uuid", - "type": "string" - }, - "repo": { - "description": "Optional repository context.", - "type": "string" - } - }, - "required": [ - "ask" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, - "channel": { - "default": "notification", - "enum": [ - "notification", - "call" - ], - "type": "string" - }, - "waiting": { - "default": "none", - "description": "hard requests a call even when channel is notification; user permissions and ring cooldowns still apply.", - "enum": [ - "none", - "hard" - ], - "type": "string" - } - }, - "required": [ - "asks" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "deliveryId": { - "format": "uuid", - "type": "string" - } - }, - "required": [ - "deliveryId" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "asks": { + "description": "The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy.", + "items": { + "additionalProperties": false, + "properties": { + "answers": { + "description": "Your reply answers a question the person asked you: the id the conversation shows for it (8 characters or whole). Their question closes with this reply as its answer, and any decision of yours it was holding back goes back to them. Needs parentId: the Goal the question is on. The reply is sent to them as it is; to also ask something new, send that as its own ask.", + "pattern": "^[0-9a-fA-F-]{8,36}$", + "type": "string" + }, + "ask": { + "description": "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy reads every ask once and takes a bundled one apart into its own cards anyway — each question a Question on the one Goal the ask lands on, never a Goal of its own — but the words it splits are its reading, not yours. News, progress and findings are their own contact; ANY contact for a person already on a call JOINS that call, whatever channel you asked for, so several arrive as one call.", + "maxLength": 10000, + "minLength": 1, + "type": "string" + }, + "id": { + "description": "Optional idempotency key or client-side ID for this specific ask.", + "type": "string" + }, + "options": { + "items": { + "additionalProperties": false, + "properties": { + "hint": { + "description": "Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').", + "maxLength": 500, + "type": "string" + }, + "html": { + "description": "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images — inline CSS and data: URIs only; <=16KB. Rendered edge-to-edge in a responsive card that is 200pt tall (about 320pt wide on a phone, with the next option peeking beside it); make your HTML fit that viewport. Use for layout/CSS mockups, tables, diffs. For a hosted image use `image` instead.", + "maxLength": 16384, + "type": "string" + }, + "image": { + "description": "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use `html` instead.", + "format": "uri", + "type": "string" + }, + "label": { + "maxLength": 1000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "label" + ], + "type": "object" + }, + "maxItems": 6, + "minItems": 1, + "type": "array" + }, + "parentId": { + "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", + "format": "uuid", + "type": "string" + }, + "repo": { + "description": "Optional repository context.", + "type": "string" + }, + "select": { + "description": "How the options are answered: \"one\" (default) to pick one, \"many\" to tick any number of them. Use \"many\" when the options are independent things they may want several of — never combinations of them like \"all three\" or \"1 and 3\". Ignored without options.", + "enum": [ + "one", + "many" + ], + "type": "string" + } + }, + "required": [ + "ask" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "channel": { + "default": "notification", + "enum": [ + "notification", + "call" + ], + "type": "string" + }, + "waiting": { + "default": "none", + "description": "hard requests a call even when channel is notification; user permissions and ring cooldowns still apply.", + "enum": [ + "none", + "hard" + ], + "type": "string" + } + }, + "required": [ + "asks" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "deliveryId": { + "format": "uuid", + "type": "string" + } + }, + "required": [ + "deliveryId" + ], + "type": "object" + } +]
3 tool updates
v1.0.10- Changed
contact1 field changed- changed
Input schema / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "asks": { - "description": "The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy.", - "items": { - "additionalProperties": false, - "properties": { - "ask": { - "description": "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy reads every ask once and takes a bundled one apart into its own cards anyway — parts of one piece of work under one Goal, separate things as separate Goals — but the words it splits are its reading, not yours. News, progress and findings are their own contact; a call contact JOINS a call already happening, so several arrive as one call.", - "maxLength": 10000, - "minLength": 1, - "type": "string" - }, - "id": { - "description": "Optional idempotency key or client-side ID for this specific ask.", - "type": "string" - }, - "options": { - "items": { - "additionalProperties": false, - "properties": { - "hint": { - "description": "Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').", - "maxLength": 500, - "type": "string" - }, - "html": { - "description": "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images — inline CSS and data: URIs only; <=16KB. Rendered edge-to-edge in a responsive card that is 200pt tall (about 320pt wide on a phone, with the next option peeking beside it); make your HTML fit that viewport. Use for layout/CSS mockups, tables, diffs. For a hosted image use `image` instead.", - "maxLength": 16384, - "type": "string" - }, - "image": { - "description": "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use `html` instead.", - "format": "uri", - "type": "string" - }, - "label": { - "maxLength": 1000, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "label" - ], - "type": "object" - }, - "maxItems": 6, - "minItems": 2, - "type": "array" - }, - "parentId": { - "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", - "format": "uuid", - "type": "string" - }, - "repo": { - "description": "Optional repository context.", - "type": "string" - } - }, - "required": [ - "ask" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, - "channel": { - "default": "notification", - "enum": [ - "notification", - "call" - ], - "type": "string" - }, - "waiting": { - "default": "none", - "enum": [ - "none", - "hard" - ], - "type": "string" - } - }, - "required": [ - "asks" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "deliveryId": { - "format": "uuid", - "type": "string" - } - }, - "required": [ - "deliveryId" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "asks": { + "description": "The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy.", + "items": { + "additionalProperties": false, + "properties": { + "ask": { + "description": "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy reads every ask once and takes a bundled one apart into its own cards anyway — each question a Question on the one Goal the ask lands on, never a Goal of its own — but the words it splits are its reading, not yours. News, progress and findings are their own contact; ANY contact for a person already on a call JOINS that call, whatever channel you asked for, so several arrive as one call.", + "maxLength": 10000, + "minLength": 1, + "type": "string" + }, + "id": { + "description": "Optional idempotency key or client-side ID for this specific ask.", + "type": "string" + }, + "options": { + "items": { + "additionalProperties": false, + "properties": { + "hint": { + "description": "Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').", + "maxLength": 500, + "type": "string" + }, + "html": { + "description": "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images — inline CSS and data: URIs only; <=16KB. Rendered edge-to-edge in a responsive card that is 200pt tall (about 320pt wide on a phone, with the next option peeking beside it); make your HTML fit that viewport. Use for layout/CSS mockups, tables, diffs. For a hosted image use `image` instead.", + "maxLength": 16384, + "type": "string" + }, + "image": { + "description": "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use `html` instead.", + "format": "uri", + "type": "string" + }, + "label": { + "maxLength": 1000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "label" + ], + "type": "object" + }, + "maxItems": 6, + "minItems": 1, + "type": "array" + }, + "parentId": { + "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", + "format": "uuid", + "type": "string" + }, + "repo": { + "description": "Optional repository context.", + "type": "string" + } + }, + "required": [ + "ask" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "channel": { + "default": "notification", + "enum": [ + "notification", + "call" + ], + "type": "string" + }, + "waiting": { + "default": "none", + "description": "hard requests a call even when channel is notification; user permissions and ring cooldowns still apply.", + "enum": [ + "none", + "hard" + ], + "type": "string" + } + }, + "required": [ + "asks" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "deliveryId": { + "format": "uuid", + "type": "string" + } + }, + "required": [ + "deliveryId" + ], + "type": "object" + } +]
- Changed
get_goal1 field changed- added
Input schema / properties / diagnoseAdded value: +{ + "type": "boolean" +}
- Changed
update_goal1 field changed- added
Input schema / properties / changes / properties / withdrawAdded value: +{ + "items": { + "pattern": "^[0-9a-fA-F-]{8,36}$", + "type": "string" + }, + "maxItems": 10, + "minItems": 1, + "type": "array" +}
1 tool update
v1.0.9- Changed
get_goal1 field changed- added
Input schema / properties / historyAdded value: +{ + "type": "boolean" +}
1 tool update
v1.0.7- Changed
contact1 field changed- changed
Input schema / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "asks": { - "description": "The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy.", - "items": { - "additionalProperties": false, - "properties": { - "ask": { - "description": "The question, and only what is needed to answer it. News, progress and findings are their own contact — a call contact JOINS a call already happening, so several arrive as one call. Do not bundle: a DecisionNeed is settled only by an answer in the shape this ask declares, so someone who answers the part that interested them settles nothing and is asked again.", - "maxLength": 10000, - "minLength": 1, - "type": "string" - }, - "id": { - "description": "Optional idempotency key or client-side ID for this specific ask.", - "type": "string" - }, - "options": { - "items": { - "additionalProperties": false, - "properties": { - "hint": { - "description": "Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').", - "maxLength": 500, - "type": "string" - }, - "html": { - "description": "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images — inline CSS and data: URIs only; <=16KB. Rendered edge-to-edge in a responsive card that is 200pt tall (about 320pt wide on a phone, with the next option peeking beside it); make your HTML fit that viewport. Use for layout/CSS mockups, tables, diffs. For a hosted image use `image` instead.", - "maxLength": 16384, - "type": "string" - }, - "image": { - "description": "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use `html` instead.", - "format": "uri", - "type": "string" - }, - "label": { - "maxLength": 1000, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "label" - ], - "type": "object" - }, - "maxItems": 6, - "minItems": 2, - "type": "array" - }, - "parentId": { - "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", - "format": "uuid", - "type": "string" - }, - "repo": { - "description": "Optional repository context.", - "type": "string" - } - }, - "required": [ - "ask" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, - "channel": { - "default": "notification", - "enum": [ - "notification", - "call" - ], - "type": "string" - }, - "waiting": { - "default": "none", - "enum": [ - "none", - "hard" - ], - "type": "string" - } - }, - "required": [ - "asks" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "deliveryId": { - "format": "uuid", - "type": "string" - } - }, - "required": [ - "deliveryId" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "asks": { + "description": "The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy.", + "items": { + "additionalProperties": false, + "properties": { + "ask": { + "description": "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy reads every ask once and takes a bundled one apart into its own cards anyway — parts of one piece of work under one Goal, separate things as separate Goals — but the words it splits are its reading, not yours. News, progress and findings are their own contact; a call contact JOINS a call already happening, so several arrive as one call.", + "maxLength": 10000, + "minLength": 1, + "type": "string" + }, + "id": { + "description": "Optional idempotency key or client-side ID for this specific ask.", + "type": "string" + }, + "options": { + "items": { + "additionalProperties": false, + "properties": { + "hint": { + "description": "Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').", + "maxLength": 500, + "type": "string" + }, + "html": { + "description": "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images — inline CSS and data: URIs only; <=16KB. Rendered edge-to-edge in a responsive card that is 200pt tall (about 320pt wide on a phone, with the next option peeking beside it); make your HTML fit that viewport. Use for layout/CSS mockups, tables, diffs. For a hosted image use `image` instead.", + "maxLength": 16384, + "type": "string" + }, + "image": { + "description": "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use `html` instead.", + "format": "uri", + "type": "string" + }, + "label": { + "maxLength": 1000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "label" + ], + "type": "object" + }, + "maxItems": 6, + "minItems": 2, + "type": "array" + }, + "parentId": { + "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", + "format": "uuid", + "type": "string" + }, + "repo": { + "description": "Optional repository context.", + "type": "string" + } + }, + "required": [ + "ask" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "channel": { + "default": "notification", + "enum": [ + "notification", + "call" + ], + "type": "string" + }, + "waiting": { + "default": "none", + "enum": [ + "none", + "hard" + ], + "type": "string" + } + }, + "required": [ + "asks" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "deliveryId": { + "format": "uuid", + "type": "string" + } + }, + "required": [ + "deliveryId" + ], + "type": "object" + } +]
4 tool updates
v1.0.6- Changed
contact1 field changed- changed
Input schema / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "asks": { - "description": "The list of asks/questions to pose. They will be semantically clustered by the API.", - "items": { - "additionalProperties": false, - "properties": { - "ask": { - "description": "The question, and only what is needed to answer it. News, progress and findings are their own contact — a call contact JOINS a call already happening, so several arrive as one call. Do not bundle: a DecisionNeed is settled only by an answer in the shape this ask declares, so someone who answers the part that interested them settles nothing and is asked again.", - "maxLength": 10000, - "minLength": 1, - "type": "string" - }, - "id": { - "description": "Optional idempotency key or client-side ID for this specific ask.", - "type": "string" - }, - "options": { - "items": { - "additionalProperties": false, - "properties": { - "hint": { - "description": "Optional short projection of consequence or action if this option is chosen.", - "maxLength": 500, - "type": "string" - }, - "html": { - "description": "Optional sandboxed HTML/CSS preview. No JavaScript or network; inline CSS and data: URIs only. It renders edge-to-edge in a responsive card 200pt tall (about 320pt wide on a phone, with the next option peeking beside it), so fit the HTML to that viewport.", - "maxLength": 16384, - "type": "string" - }, - "image": { - "format": "uri", - "type": "string" - }, - "label": { - "maxLength": 1000, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "label" - ], - "type": "object" - }, - "maxItems": 6, - "minItems": 2, - "type": "array" - }, - "parentId": { - "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", - "format": "uuid", - "type": "string" - }, - "repo": { - "description": "Optional repository context.", - "type": "string" - } - }, - "required": [ - "ask" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, - "channel": { - "default": "notification", - "enum": [ - "notification", - "call" - ], - "type": "string" - }, - "waiting": { - "default": "none", - "enum": [ - "none", - "hard" - ], - "type": "string" - } - }, - "required": [ - "asks" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "deliveryId": { - "format": "uuid", - "type": "string" - } - }, - "required": [ - "deliveryId" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "asks": { + "description": "The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy.", + "items": { + "additionalProperties": false, + "properties": { + "ask": { + "description": "The question, and only what is needed to answer it. News, progress and findings are their own contact — a call contact JOINS a call already happening, so several arrive as one call. Do not bundle: a DecisionNeed is settled only by an answer in the shape this ask declares, so someone who answers the part that interested them settles nothing and is asked again.", + "maxLength": 10000, + "minLength": 1, + "type": "string" + }, + "id": { + "description": "Optional idempotency key or client-side ID for this specific ask.", + "type": "string" + }, + "options": { + "items": { + "additionalProperties": false, + "properties": { + "hint": { + "description": "Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').", + "maxLength": 500, + "type": "string" + }, + "html": { + "description": "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images — inline CSS and data: URIs only; <=16KB. Rendered edge-to-edge in a responsive card that is 200pt tall (about 320pt wide on a phone, with the next option peeking beside it); make your HTML fit that viewport. Use for layout/CSS mockups, tables, diffs. For a hosted image use `image` instead.", + "maxLength": 16384, + "type": "string" + }, + "image": { + "description": "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use `html` instead.", + "format": "uri", + "type": "string" + }, + "label": { + "maxLength": 1000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "label" + ], + "type": "object" + }, + "maxItems": 6, + "minItems": 2, + "type": "array" + }, + "parentId": { + "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", + "format": "uuid", + "type": "string" + }, + "repo": { + "description": "Optional repository context.", + "type": "string" + } + }, + "required": [ + "ask" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "channel": { + "default": "notification", + "enum": [ + "notification", + "call" + ], + "type": "string" + }, + "waiting": { + "default": "none", + "enum": [ + "none", + "hard" + ], + "type": "string" + } + }, + "required": [ + "asks" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "deliveryId": { + "format": "uuid", + "type": "string" + } + }, + "required": [ + "deliveryId" + ], + "type": "object" + } +]
- Removed
get_thread - Added
listen - Removed
search_threads
11 tool updates
v1.0.5- Removed
answer_caller_question - Removed
await_reply - Added
claim_goal - Changed
contact3 fields changed- added
Input schema / anyOfAdded value: +[ + { + "additionalProperties": false, + "properties": { + "asks": { + "description": "The list of asks/questions to pose. They will be semantically clustered by the API.", + "items": { + "additionalProperties": false, + "properties": { + "ask": { + "description": "The question, and only what is needed to answer it. News, progress and findings are their own contact — a call contact JOINS a call already happening, so several arrive as one call. Do not bundle: a DecisionNeed is settled only by an answer in the shape this ask declares, so someone who answers the part that interested them settles nothing and is asked again.", + "maxLength": 10000, + "minLength": 1, + "type": "string" + }, + "id": { + "description": "Optional idempotency key or client-side ID for this specific ask.", + "type": "string" + }, + "options": { + "items": { + "additionalProperties": false, + "properties": { + "hint": { + "description": "Optional short projection of consequence or action if this option is chosen.", + "maxLength": 500, + "type": "string" + }, + "html": { + "description": "Optional sandboxed HTML/CSS preview. No JavaScript or network; inline CSS and data: URIs only. It renders edge-to-edge in a responsive card 200pt tall (about 320pt wide on a phone, with the next option peeking beside it), so fit the HTML to that viewport.", + "maxLength": 16384, + "type": "string" + }, + "image": { + "format": "uri", + "type": "string" + }, + "label": { + "maxLength": 1000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "label" + ], + "type": "object" + }, + "maxItems": 6, + "minItems": 2, + "type": "array" + }, + "parentId": { + "description": "The Goal this question is about — usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself.", + "format": "uuid", + "type": "string" + }, + "repo": { + "description": "Optional repository context.", + "type": "string" + } + }, + "required": [ + "ask" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "channel": { + "default": "notification", + "enum": [ + "notification", + "call" + ], + "type": "string" + }, + "waiting": { + "default": "none", + "enum": [ + "none", + "hard" + ], + "type": "string" + } + }, + "required": [ + "asks" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "deliveryId": { + "format": "uuid", + "type": "string" + } + }, + "required": [ + "deliveryId" + ], + "type": "object" + } +] - removed
Input schema / propertiesRemoved value: -{ - "ask": { - "description": "What to tell the user, or what you need to find out from them. Plain prose — as long as it needs to be (up to 10k characters); Paigy splits it into topics and reads back a few sentences at a time, so do NOT compress a briefing into one line. May be spoken aloud on a call, so write natural speech and name things (not IDs). Contact at exactly two moments: BLOCKED on a decision only they can make, or DONE (one short report — what shipped, how you verified it, what you flagged). DONE IS SAID ONCE: \"all set\", \"nothing open on my end\", \"that thread is complete\" are the same report in new words, and each one reaches them separately (live 2026-08-12: three of them in three minutes). After the first, you are finished speaking; if they acknowledge it, stop rather than confirming the acknowledgement. Progress is never a contact: set_task_state carries it, and working narration stays in your own terminal — the user sees you're working without being interrupted by it.", - "type": "string" - }, - "channel": { - "description": "Only if the user explicitly said how to reach them — 'call me' → 'call', 'just message/text me' → 'message'. Omit otherwise; Paigy picks.", - "enum": [ - "call", - "message" - ], - "type": "string" - }, - "options": { - "description": "The choices the user picks from, when you have them.", - "items": { - "properties": { - "html": { - "description": "Optional sandboxed HTML/CSS preview (no JS, no network, inline CSS + data: URIs, ≤16KB).", - "type": "string" - }, - "image": { - "description": "Optional hosted image URL shown as this option's preview.", - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "label" - ], - "type": "object" - }, - "type": "array" - }, - "parentId": { - "description": "To continue an earlier conversation, pass the parentId a previous contact or reply returned. Omit to start a new one.", - "type": "string" - }, - "waiting": { - "description": "What happens to your work while you wait. 'none': you're just informing them. 'soft': you'd like an answer but can keep working. 'hard': you are STOPPED until they answer — reaches them urgently and escalates to a real phone call if unanswered.", - "enum": [ - "none", - "soft", - "hard" - ], - "type": "string" - } -} - removed
Input schema / requiredRemoved value: -[ - "ask" -]
- Added
create_goal - Added
get_goal - Changed
get_thread1 field changed- changed
Input schema / properties / parentId / descriptionPrevious value: -"The thread to read — from a reply, request, or past notification."New value: +"The Thread to read — the parentId of a search_threads hit."
- Removed
handoff - Removed
schedule_callback - Removed
set_task_state - Added
update_goal
11 tool updates
v1.0.3- Added
answer_caller_question - Added
await_reply - Changed
contact3 fields changed- changed
Input schema / properties / ask / descriptionPrevious value: -"What to tell the user, or what you need to find out from them. Plain prose, one or two sentences; may be spoken aloud on a call, so write natural speech and name things (not IDs)."New value: +"What to tell the user, or what you need to find out from them. Plain prose — as long as it needs to be (up to 10k characters); Paigy splits it into topics and reads back a few sentences at a time, so do NOT compress a briefing into one line. May be spoken aloud on a call, so write natural speech and name things (not IDs). Contact at exactly two moments: BLOCKED on a decision only they can make, or DONE (one short report — what shipped, how you verified it, what you flagged). DONE IS SAID ONCE: \"all set\", \"nothing open on my end\", \"that thread is complete\" are the same report in new words, and each one reaches them separately (live 2026-08-12: three of them in three minutes). After the first, you are finished speaking; if they acknowledge it, stop rather than confirming the acknowledgement. Progress is never a contact: set_task_state carries it, and working narration stays in your own terminal — the user sees you're working without being interrupted by it." - added
Input schema / properties / parentIdAdded value: +{ + "description": "To continue an earlier conversation, pass the parentId a previous contact or reply returned. Omit to start a new one.", + "type": "string" +} - removed
Input schema / properties / threadIdRemoved value: -{ - "description": "To continue an earlier conversation, pass the threadId a previous contact or reply returned. Omit to start a new one.", - "type": "string" -}
- Removed
enable_tools - Added
get_thread - Changed
handoff2 fields changed- added
Input schema / properties / parentIdAdded value: +{ + "format": "uuid", + "type": "string" +} - removed
Input schema / properties / threadIdRemoved value: -{ - "format": "uuid", - "type": "string" -}
- Added
onboard - Changed
pair2 fields changed- added
Input schema / properties / nameAdded value: +{ + "description": "Hatch path only: the name you choose for this identity. Pick your own — ONE or TWO words, the way you'd introduce yourself on a call (it is spoken aloud and shown in lists). 'Piper', 'Blue Heron' — never a sentence or a task description.", + "maxLength": 60, + "minLength": 1, + "type": "string" +} - added
Input schema / properties / voiceAdded value: +{ + "description": "Hatch path only: your voice on calls — one of rachel, george, jessica, brian, lily.", + "type": "string" +}
- Added
schedule_callback - Added
search_threads - Added
unpair
5 tool updates
v1.0.2- Added
contact - Added
handoff - Added
pair - Removed
schedule_callback - Removed
unpair
5 tool updates
v1.0.1- Added
enable_tools - Removed
get_thread - Removed
handoff - Added
schedule_callback - Added
unpair
9 tool updates
v1.0.1- Removed
await_reply - Added
get_thread - Added
handoff - Removed
notify_user - Removed
pair - Removed
poll_answer - Removed
register_delivery - Removed
schedule_callback - Removed
unpair
9 tool updates
v0.1.0- First observed
await_reply - First observed
check_replies - First observed
notify_user - First observed
pair - First observed
poll_answer - First observed
register_delivery - First observed
schedule_callback - First observed
set_task_state - First observed
unpair
TDQS
Scored across 9 tools
Most tools are clearly distinct (configure, listen, send_feedback, check_activity, search, get_goals, get_delivery), but `contact` is a mega-tool that overlaps `manage_goals` (its `completions` contract is explicitly duplicated by the `complete` kind), `get_delivery`, and partly `search`. An agent can reasonably hesitate over whether to ask/answer/close via `contact` or `manage_goals`, so boundaries are only partly clear.
All names are snake_case and readable, but conventions are mixed: bare verbs (`contact`, `configure`, `search`, `listen`) sit alongside verb_noun patterns (`manage_goals`, `get_goals`, `get_delivery`, `check_activity`, `send_feedback`). The `get_*`/`manage_*` families are internally consistent, making this a minor deviation rather than chaos.
Nine tools is a well-scoped count for a coordination/identity protocol and each tool has a recognizable role. The only pressure point is that `contact` absorbs sending, receiving, answering, withdrawing, completions, and waiting, which is arguably several tools' worth of responsibility in one.
The surface covers the domain well: identity setup/logout, goal CRUD with dependencies/assign/defer/complete, reading goals and deliveries, history search, activity, listening, and feedback. Minor gaps exist (no standalone withdraw-question or goal-delete operation; those are folded into `contact`/`state`), but no workflow is a dead end.
Maintenance
Related MCP Connectors
- call-meOAuthapp.getcallme
Calls your phone when an AI task finishes or is blocked — hear it, say what's next.
Your agent asks you a question on your phone, waits for the answer, then resumes.
Your agent asks you before it acts. You answer with one tap on your phone. Human-in-the-loop.
- iotPushOAuthcom.iotpush
Notifications you can answer: agents push to your phone and wait for your approval or reply.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceHuman-in-the-loop approvals and notifications for AI agents via WhatsApp. Enables Cursor, Claude Code, and autonomous AI agents to reach users away from their computers.19 npmISC
- AlicenseNot gradedqualityDmaintenanceA human-in-the-loop input gateway for AI coding agents that lets agents pause mid-task and ask questions via a native Android app, designed for away-from-desk workflows.MIT
- AlicenseNot gradedqualityAmaintenanceEnables agents to pause and ask a human for a decision, then resume with the answer, via a self-hosted SQLite-backed MCP server with console or phone interfaces.1AGPL 3.0

tmgr-notifyofficial
AlicenseBqualityBmaintenanceEnables AI agents to reach users on their phone through push notifications, and to raise urgent, escalating alarms that fall back to a voice call until someone acknowledges. It also ships hooks that notify users automatically when Claude Code or Codex needs input or finishes a turn.341 npmMIT