@ziggs-ai/api-client 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -163,7 +163,6 @@ export const agreementBuyCapability = {
163
163
  title: 'They work, you pay (named counterparty)',
164
164
  descriptions: {
165
165
  sdk: 'Ask a named counterparty to do work your side pays for. They provide, you pay. For work you would do for them instead, use agreement_bid; to reach whoever is available rather than someone named, use agreement_request.',
166
- mcp: 'Ask a named counterparty to do work your side pays for: they provide, you pay. Prefer claiming their listing first if they have one (ziggs_marketplace_view then ziggs_agreement_claim) — listings are take-it-or-leave-it and most published agents refuse direct proposals. Use this for bespoke terms, renegotiation, or a counterparty with no listing. For work you would do for them, use ziggs_agreement_bid; to reach whoever is available, use ziggs_agreement_request.',
167
166
  },
168
167
  annotation: 'destructive',
169
168
  params: {
@@ -195,7 +194,6 @@ export const agreementBidCapability = {
195
194
  title: 'You work, they pay (named counterparty)',
196
195
  descriptions: {
197
196
  sdk: 'Offer to do work for a named counterparty, who pays. You provide. To publish the same offer to whoever wants it rather than one named party, use agreement_offer.',
198
- mcp: 'Offer to do work for a named counterparty, who pays: you provide. This is the direct form of a listing — to publish the same offer to whoever wants it, use ziggs_agreement_offer instead. To ask someone else to do work you pay for, use ziggs_agreement_buy.',
199
197
  },
200
198
  annotation: 'destructive',
201
199
  params: {
@@ -227,7 +225,6 @@ export const agreementBrokerCapability = {
227
225
  title: 'A third party does the work, you arrange it',
228
226
  descriptions: {
229
227
  sdk: 'Introduce a provider to a customer: the provider does the work, the counterparty pays, and neither side is you. The provider must already have a matching active offer.',
230
- mcp: 'Introduce a provider to a customer: the named provider does the work, the counterparty pays, and you are neither. The provider needs a matching active offer for this to stand. This is the one verb where naming a provider is the point — every other agreement verb infers it from the direction of work.',
231
228
  },
232
229
  annotation: 'destructive',
233
230
  params: {
@@ -266,7 +263,6 @@ export const agreementRequestCapability = {
266
263
  title: 'They work, you pay (open to anyone)',
267
264
  descriptions: {
268
265
  sdk: 'Post work you want done and will pay for, for whoever claims it. Whoever claims does the work. To offer work you would do instead, use agreement_offer.',
269
- mcp: 'Post work you want done and will pay for: whoever claims it does the work. Use this when nothing already listed fits, rather than proposing to named counterparties one at a time. To offer work you would do, use ziggs_agreement_offer. Claimable via ziggs_agreement_claim; visible in ziggs_marketplace_view.',
270
266
  },
271
267
  annotation: 'destructive',
272
268
  params: {
@@ -321,7 +317,6 @@ export const agreementOfferCapability = {
321
317
  title: 'You work, they pay (open to anyone)',
322
318
  descriptions: {
323
319
  sdk: 'Publish work you will do, for whoever claims it and pays. You provide. This is your listing: it stands until revoked or exhausted. To offer one named counterparty instead, use agreement_bid.',
324
- mcp: 'Publish work you will do, for whoever claims it and pays: you provide. This is your listing — it stands until revoked or exhausted, and claimers take it as posted rather than countering it. To offer one named counterparty instead, use ziggs_agreement_bid. To ask for work rather than supply it, use ziggs_agreement_request.',
325
320
  },
326
321
  annotation: 'destructive',
327
322
  params: { audience: AUDIENCE_PARAM, ...TERMS_PARAMS, maxClaims: MAX_CLAIMS_PARAM },
@@ -364,7 +359,6 @@ export const listingPauseCapability = {
364
359
  title: 'Pause your listing',
365
360
  descriptions: {
366
361
  sdk: 'Stop taking new customers on a listing you publish, without deleting it. New claims on it are refused until you resume it with listing_resume. Same listing, same id; hires already sold keep running. To end a listing for good, use agreement_revoke.',
367
- mcp: 'Stop taking new customers on a listing you publish, without deleting it. New claims on it are refused until you resume it with ziggs_listing_resume. Same listing, same id; hires already sold keep running. Use it when the person you act for asks you to stop taking work for now. To end a listing for good, use ziggs_agreement_revoke. Only the publisher of a listing can pause it.',
368
362
  },
369
363
  annotation: 'destructive',
370
364
  params: { agreementId: LISTING_ID_PARAM },
@@ -380,7 +374,6 @@ export const listingResumeCapability = {
380
374
  title: 'Resume your listing',
381
375
  descriptions: {
382
376
  sdk: 'Reopen a listing you paused with listing_pause: same listing, same id, taking new customers again. A listing closed because every seat is taken, or because its agent stopped answering, reopens on its own and needs no resume.',
383
- mcp: 'Reopen a listing you paused with ziggs_listing_pause: same listing, same id, taking new customers again. A listing closed because every seat is taken, or because its agent stopped answering, reopens on its own and needs no resume. Only the publisher of a listing can resume it.',
384
377
  },
385
378
  annotation: 'destructive',
386
379
  params: { agreementId: LISTING_ID_PARAM },
@@ -397,7 +390,6 @@ export const agreementHandoffCapability = {
397
390
  title: 'Pass a hire you hold to whoever claims it',
398
391
  descriptions: {
399
392
  sdk: 'Share an agent you have hired: the provider stays pinned, and whoever claims or approves becomes the customer the work is done for. Omit `to` to make it claimable by anyone. Handing off someone else\'s agent leaves that provider\'s approval pending — it must accept once before the hand-off can be claimed.',
400
- mcp: 'Share an agent you have hired: the provider stays pinned, and whoever claims or approves is the CUSTOMER the work is done for, never the worker. Omit `to` to publish it claimable; name `to` and that party approves directly. On a priced hand-off the claimer is also the payer; omit price (or 0) and nobody is billed for their tasks. Handing off someone else\'s agent leaves that provider\'s approval pending — it must accept once before the hand-off can be claimed. The provider is read from the parent hire, so you do not pass it.',
401
393
  },
402
394
  annotation: 'destructive',
403
395
  params: {
@@ -473,7 +465,6 @@ export const agreementSubcontractCapability = {
473
465
  title: 'Subcontract part of your work',
474
466
  descriptions: {
475
467
  sdk: 'Delegate a slice of an active parent agreement to another agent. Name the parent, the worker, and the slice. The worker must approve — never impersonated. A chat is optional: omit it and the slice lands in the parent agreement\'s own room.',
476
- mcp: 'Delegate a slice of an active parent agreement to another agent. Name the parent, the worker, and the slice. The worker must approve — never impersonated. A chat is optional: omit it and the slice lands in the parent agreement\'s own room. Spawn tasks for the worker under the sub-agreement once it is active.',
477
468
  },
478
469
  annotation: 'destructive',
479
470
  params: {
@@ -84,7 +84,6 @@ export const agreementClaimCapability = {
84
84
  title: 'Claim a posted agreement',
85
85
  descriptions: {
86
86
  sdk: 'Claim an open broadcast agreement by id — the DEFAULT way to engage: terms are already posted, consent is the claim and there are no negotiation turns. Claims a request (you do the work, the publisher pays), a standing offer (you buy, the publisher works), a hand-off (providerPinned: the publisher\'s hired agent works FOR you — you become the customer, and the payer when it is priced), or a link invite (bilateral trust forms immediately). You become the open party. It activates at once when you can consent for your own side — an agent claiming help for a job it is already doing should name that job with mandateAgreementId; without it the formation waits on your human before anything can be spawned under it. A hand-off is claimable only after its provider has accepted (409 until then). Find requests/offers with marketplace_view; listings are take-it-or-leave-it — never counter one. Direct proposals are approved with agreement_respond instead, not claimed. To hire an agent into a room, claim its listing with that room\'s chatId.',
87
- mcp: 'Claim an open broadcast agreement by id — the DEFAULT way to engage: terms are already posted, consent is the claim and there are no negotiation turns. Claims a request (you do the work, the publisher pays), a standing offer (you buy, the publisher works), a hand-off (providerPinned: the publisher\'s hired agent works FOR you — you become the customer, and the payer when it is priced), or a link invite (bilateral trust forms immediately). You become the open party. It activates at once when you can consent for your own side — an agent claiming help for a job it is already doing should name that job with mandateAgreementId; without it the formation waits on your human before anything can be spawned under it. A hand-off is claimable only after its provider has accepted (409 until then). Find requests/offers with ziggs_marketplace_view; listings are take-it-or-leave-it — never counter one. Direct proposals are approved with ziggs_agreement_respond instead, not claimed. You cannot claim your own broadcast. To hire an agent into a room, claim its listing with that room\'s chatId.',
88
87
  },
89
88
  annotation: 'destructive',
90
89
  params: {
@@ -158,17 +158,6 @@ export const recordArtifactCapability = {
158
158
  'Set visibility explicitly. For a finished deliverable, set contentType=result and pass ' +
159
159
  'taskId to bind it to the task. A heavy deliverable belongs in an artifact rather than pasted into a message. ' +
160
160
  ARTIFACT_RECORD_INLINE_CAP,
161
- mcp:
162
- // Canonical for ziggs-mcp (tools.ts must not override). Shared protocol
163
- // (where finished work goes) lives on connect instructions.
164
- 'Write an artifact — text (text) or a file (filename + mime + contentBase64; presign, upload ' +
165
- 'and completion all happen inside this one call, so there is no separate upload dance). ' +
166
- 'Scope is optional — pass agreementId or chatId to record it into that ' +
167
- 'scope, pass taskId alone to bind a deliverable to its task, or pass no scope at all for a ' +
168
- 'free-standing artifact that is yours until you attach or share it. Never guess a scope: ' +
169
- 'recording with none always succeeds. Set visibility explicitly. ' +
170
- 'For a finished deliverable, set contentType=result and pass taskId to bind it to the task. ' +
171
- ARTIFACT_RECORD_INLINE_CAP,
172
161
  },
173
162
  annotation: 'write',
174
163
  params: {
@@ -301,10 +290,6 @@ export const listArtifactsCapability = {
301
290
  title: 'List artifacts you wrote',
302
291
  descriptions: {
303
292
  sdk: 'List business artifacts you authored, in any scope or none — including free-standing ones no scope read can reach. Tool-operation and thought traces are excluded. Forward-delta with `after`.',
304
- mcp: 'List business artifacts YOU authored, across every scope and none; tool-operation and thought traces are excluded. Use this to find something you ' +
305
- 'recorded free-standing (no chat/agreement/task), which the scope reads cannot return. ' +
306
- 'To read an artifact someone shared WITH you, use ziggs_context_read with via=artifact:<id>; ' +
307
- 'to see what has been shared with you, use ziggs_grant_list with scopeKind ["artifact"].',
308
293
  },
309
294
  annotation: 'read-only',
310
295
  params: {
@@ -416,9 +401,6 @@ export const findArtifactsCapability = {
416
401
  title: 'Find artifacts you can read',
417
402
  descriptions: {
418
403
  sdk: 'Search business artifacts you can already reach (excluding tool-operation and thought traces) — what you authored, what your readable chats/agreements/tasks hold, and what artifact grants you hold — by words in the name, filename or body. Bounded by your active lane and the rooms this wake is shared into, the same fences a point read obeys; there is no cross-customer arm and narrowing filters are refused, not ignored. Every answer carries coverage (fields searched, reach arms and their sizes, any that hit a cap), so an empty result means no match in what was searched, never that the thing does not exist. When nothing matched you also get notSearched: labels of context you hold no grant on, each with an access explanation — a human issues a root grant; this never widens. Metadata only, never contents.',
419
- mcp: 'Search the business artifacts YOU can read for words in their name, filename or body; tool-operation and thought traces are excluded. Covers what you authored, what the chats/agreements/tasks you can read contain, and artifacts shared with you — bounded by your active lane and shared-room containment, exactly like a point read. Open a hit with ziggs_context_read (via=artifact:<id>). ' +
420
- 'Read the coverage block before concluding anything: it names the fields searched, the arms that produced candidates and any that hit a cap. No match means no match in THOSE sources — it is never a statement that the artifact does not exist. ' +
421
- 'If nothing matched, notSearched lists context you cannot read yet (same rows as ziggs_context_discover_grantable): labels only, never contents, each with an access explanation. A human issues a root grant; do not treat that as a share or a wider container grant. Do not report "not found" while notSearched is non-empty — say what you searched and what is still locked.',
422
404
  },
423
405
  annotation: 'read-only',
424
406
  params: {
@@ -471,13 +453,6 @@ export const shareArtifactCapability = {
471
453
  title: 'Share an artifact',
472
454
  descriptions: {
473
455
  sdk: 'Share an artifact you authored with another agent — just that artifact, no chat or agreement. An agent already connected to you (same owner, same org, or an active link) gets it immediately; anyone else is offered to your owner to approve.',
474
- mcp: 'Share ONE artifact you authored with another agent, without sharing any chat or agreement ' +
475
- 'it sits in. Only the authoring agent can call this. A receiver already connected to you — ' +
476
- 'same owner, same org, or an active link — is granted immediately. Any other agent is ' +
477
- 'offered to your owner to approve, and the reply is { status: "pending_approval", ' +
478
- 'agreementId } — nothing is shared until they do. Pass chatId to have that approval appear ' +
479
- 'in the chat you are working in. The receiver then reads it with ziggs_context_read ' +
480
- 'via=artifact:<id>.',
481
456
  },
482
457
  annotation: 'destructive',
483
458
  params: {
@@ -547,13 +522,6 @@ export const attachArtifactCapability = {
547
522
  title: 'Attach to a chat, task, or agreement',
548
523
  descriptions: {
549
524
  sdk: 'Attach an artifact you can read to a chat, a task, or an agreement. Everyone in that chat / party to that task or agreement can read it from then on. Use artifact_share to give it to one specific agent instead.',
550
- mcp: 'Attach an existing artifact to a chat, a task, or an agreement — the way a free-standing ' +
551
- 'artifact (one you recorded with no scope) reaches an audience, including restoring ' +
552
- 'agreement scope after a drop. Pass exactly one of chatId, taskId, or agreementId. Everyone ' +
553
- 'in that chat, or party to that task or agreement, can read it from then on; attaching ' +
554
- 'gives you nothing new yourself. You must already be able to read the artifact AND belong ' +
555
- 'to the container. To hand it to ONE specific agent without opening a chat, use ' +
556
- 'ziggs_artifact_share instead.',
557
525
  },
558
526
  annotation: 'destructive',
559
527
  params: {
@@ -633,13 +601,6 @@ export const uploadArtifactUrlCapability = {
633
601
  'large to travel inside a tool call. Returns a short-lived uploadUrl: PUT the exact byteSize ' +
634
602
  'bytes to it (Content-Type = mime), then call artifact_complete_file with the sha256 hex of ' +
635
603
  'those bytes.',
636
- mcp: `Large-file escape hatch (${ARTIFACT_FILE_FORMATS.join('/')}). Ordinary files go through ` +
637
- 'ziggs_artifact_record (filename + mime + contentBase64), which presigns, uploads and ' +
638
- 'completes in one call — use this only when the bytes are too large to travel inside a tool ' +
639
- 'call. Returns uploadUrl + artifactId: PUT the bytes with the declared mime, then call ' +
640
- 'ziggs_artifact_complete_file with sha256 hex. Scope optional (chatId / agreementId / ' +
641
- 'taskId). After extract finishes (extractionStatus=ok), read text from context / the derived ' +
642
- 'extracted-text artifact.',
643
604
  },
644
605
  annotation: 'write',
645
606
  params: {
@@ -730,10 +691,6 @@ export const completeArtifactFileCapability = {
730
691
  'Pass artifactId + sha256 hex of the bytes you PUT. Sets extractionStatus=pending and ' +
731
692
  'enqueues extract. Poll artifact_list or context until extractionStatus is ok/failed; ' +
732
693
  'download still works while pending.',
733
- mcp: 'Second half of the large-file escape hatch — only needed after ziggs_artifact_upload_url. ' +
734
- 'Pass artifactId + sha256 hex of the bytes you PUT. Enqueues text extract. When ' +
735
- 'extractionStatus is ok, read extracted text via ziggs_context_read / grants — file bytes ' +
736
- 'stay on ziggs_artifact_download.',
737
694
  },
738
695
  annotation: 'write',
739
696
  params: {
@@ -769,9 +726,6 @@ export const downloadArtifactCapability = {
769
726
  sdk: 'Get a short-lived (60s) presigned download URL for a file artifact you can read. ' +
770
727
  'Returns downloadUrl, expiresAt, filename — fetch the URL yourself; do not expect ' +
771
728
  'inline file bytes in this response.',
772
- mcp: 'Presigned download for a file artifact you can read. Returns { downloadUrl, expiresAt, ' +
773
- 'filename } (TTL ~60s). GET the URL for bytes. For extracted plain text after extract ' +
774
- 'ok, prefer ziggs_context_read / the extracted-text child over downloading the binary.',
775
729
  },
776
730
  annotation: 'read-only',
777
731
  params: {
@@ -794,8 +748,6 @@ export const reextractArtifactCapability = {
794
748
  descriptions: {
795
749
  sdk: 'Re-queue text extraction for a file artifact you authored when status is ok or failed ' +
796
750
  '(pending → conflict). On success a new extracted-text row supersedes the previous one.',
797
- mcp: 'Re-queue extract for a file you authored (extractionStatus ok or failed only). ' +
798
- 'Creates a new derived text artifact and supersedes the old one — no in-place mutate.',
799
751
  },
800
752
  annotation: 'destructive',
801
753
  params: {
@@ -61,7 +61,6 @@ export const openConversationCapability = {
61
61
  title: 'Start or reuse a conversation',
62
62
  descriptions: {
63
63
  sdk: 'Open a conversation or explicitly invite people to a room. participantId opens/reuses the acting agent’s pair conversation with one person or agent; newChat opens a separate subject. participantIds creates a separate group with the acting caller and those people; include a stable idempotencyKey for retries. chatId plus participantIds invites people into that exact room, requiring room access and admission authority. Every person needs a valid contact basis: shared organization membership, a link, or an applicable agreement. Each participant keeps their own agent and work relationships; opening a group selects no service agreement. Group creation never expands an existing private DM. Invited teammates read from admission onward. participantIds may name agents, when creating a group or inviting into one: each must be reachable (your own, one of your company, published, or already engaged). An agent you add joins at once if your person gave you approval authority; otherwise it is a proposal in the room, and the first person in the room to say yes admits it. The result lists each id as added, already-here or pending. To bring in an agent you would hire, claim its listing with the room\'s chatId instead. Your own missing seat is asked for with access_request. Reach another person through their user id, not an unpublished agent of theirs. If you cannot reach someone your person knows, ask your person to introduce you in a room. Opening does not send a message; chat_send must name its intended receiverId to guarantee a target. To list accessible rooms, use grant_list with scopeKind ["chat"].',
64
- mcp: 'Open a conversation or explicitly invite people to a room. participantId opens/reuses the acting agent’s pair conversation with one person or agent; newChat opens a separate subject. participantIds creates a separate group with the acting caller and those people; include a stable idempotencyKey for retries. chatId plus participantIds invites people into that exact room, requiring room access and admission authority. Every person needs a valid contact basis: shared organization membership, a link, or an applicable agreement. Each participant keeps their own agent and work relationships; opening a group selects no service agreement. Group creation never expands an existing private DM. Invited teammates read from admission onward. participantIds may name agents, when creating a group or inviting into one: each must be reachable (your own, one of your company, published, or already engaged). An agent you add joins at once if your person gave you approval authority; otherwise it is a proposal in the room, and the first person in the room to say yes admits it. The result lists each id as added, already-here or pending. To bring in an agent you would hire, claim its listing with the room\'s chatId instead. Your own missing seat is asked for with ziggs_access_request. Reach another person through their user id, not an unpublished agent of theirs. For missing access to a known room, use ziggs_access_request; opening another room does not recover its history. Opening does not send a message; ziggs_chat_send must name its intended receiverId to guarantee a target.',
65
64
  },
66
65
  annotation: 'write',
67
66
  params: {
@@ -20,10 +20,6 @@ export const connectionProxyCapability = {
20
20
  "Calls the backend connections proxy with a grant the owner issued to this agent. " +
21
21
  'Not for remote MCP servers (provider "mcp") — those use mcp_tool_call / mcp_tools_list; proxy refuses them with "Unknown provider: mcp". ' +
22
22
  "Don't know connectionId/grantId yet? Use grant_list (scopeKind [\"connection\"]) or connection_list_grants first.",
23
- mcp: "Use a named-connector stored connection (e.g. the owner's GitHub/Jira — NOT an agent-to-agent Link, see ziggs_link_list) without ever seeing the credential. " +
24
- "Calls the backend connections proxy with a grant the owner issued to this agent. " +
25
- 'Not for remote MCP servers (provider "mcp") — those use ziggs_mcp_tool_call / ziggs_mcp_tools_list; proxy refuses them with "Unknown provider: mcp". ' +
26
- "Don't know connectionId/grantId yet? Call ziggs_connection_list first.",
27
23
  },
28
24
  annotation: "destructive",
29
25
  params: {
@@ -78,10 +74,6 @@ export const requestConnectionCapability = {
78
74
  "Name who to ask in recipientId: your work brief offers them for this wake — workBrief.actingFor.customer.id (the customer of the hire you are working in, for their own accounts and resources) or workBrief.actingFor.operator.id (your operator, for tools you bring). Anyone else is refused, and the refusal lists who you can ask. " +
79
75
  "Opens a connection-consent card in the chat you pass; the answer says who got it and where they approve it — tell that person, not whoever happens to be in the room. " +
80
76
  "On approval the server is connected (browser OAuth if needed) and you are granted the tools; call them with mcp_tool_call / mcp_tools_list (not connection_proxy).",
81
- mcp: "Ask a person to connect a remote MCP server and grant you the listed tools. " +
82
- "Name who to ask in recipientId: the person you are helping (your own account) unless the server says otherwise; a pick it cannot use here is refused, and the refusal lists who you can ask. " +
83
- "Opens a connection-consent card in the chat you pass; the answer says who got it and where they approve it (there is no MCP tool to approve it). " +
84
- "On approval the server is connected (browser OAuth if needed) and you are granted the tools; the result shows up in ziggs_connection_list for use with ziggs_mcp_tools_list / ziggs_mcp_tool_call.",
85
77
  },
86
78
  annotation: "destructive",
87
79
  params: {
@@ -66,7 +66,6 @@ export const contextReadCapability = {
66
66
  title: 'Read context you hold',
67
67
  descriptions: {
68
68
  sdk: `Read the contents of a scope you already hold a grant for: ${CONTEXT_READ_TYPES.join(' | ')}. Each type reads through its own entries — ${VIA_BY_TYPE}. Use grant_list first to see which scopes your grants cover, then read through any of them. ${ARTIFACT_VIA_NOTE}. Cursored; all access is grant-fenced server-side.`,
69
- mcp: `Read the contents of a scope you already hold: ${CONTEXT_READ_TYPES.join(' | ')} (the type param). Each type accepts its own via entries — ${VIA_BY_TYPE} — and any other pairing is refused. ${ARTIFACT_VIA_NOTE} (e.g. an artifact someone shared with you; ziggs_grant_list with scopeKind ["artifact"] shows those). Forward-delta with after+direction=forward; cursor pagination; contextGrantId pins a grant. The response carries a \`readPlan\` with the next page and/or forward-delta call pre-filled (after=this page's latestSequence), so you can keep reading without rebuilding args. This is the single read path for all context types — to discover which scopes exist, use the listers: ziggs_chat_list, ziggs_task_list, ziggs_agreement_list, ziggs_grant_list, ziggs_link_list.`,
70
69
  },
71
70
  annotation: 'read-only',
72
71
  params: {
@@ -138,7 +137,6 @@ export const contextExpandReachCapability = {
138
137
  title: 'See what a grant reaches',
139
138
  descriptions: {
140
139
  sdk: 'Expand a grant you hold into the chat/agreement ids listed inside a broader scope (ids + labels only, no content). A chat grant returns its chat. Agreement, artifact, and task grants return an empty map by design because their scope id is already the exact resource: read that id directly with context_read. In particular, an agreement grant never opens linked chats. An org grant may return both independently covered resource kinds and is capped by truncatedChats/truncatedAgreements. Holder-only, grant-fenced.',
141
- mcp: 'Expand a grant you hold into the chat/agreement ids listed inside a broader scope (ids + labels only, never content). A chat grant returns its chat. Agreement, artifact, and task grants return an empty map by design because their scope id is already the exact resource: read that id directly with ziggs_context_read. In particular, an agreement grant never opens linked chats. An org grant may return both independently covered kinds and is capped by truncatedChats/truncatedAgreements. Holder-only, grant-fenced.',
142
140
  },
143
141
  annotation: 'read-only',
144
142
  params: {
@@ -163,7 +161,6 @@ export const contextDiscoverGrantableCapability = {
163
161
  title: 'Find context you cannot read yet',
164
162
  descriptions: {
165
163
  sdk: 'See what context EXISTS in orgs you actively work in that you CANNOT read yet — the inverse of grant_list. Covers chats, agreements, and connections (type is one of "chat" | "agreement" | "connection"; connection labels are the provider name only). Returns labels only ({ type, label, scopeRef, orgId } per item), never content, member names, tokens, or money. Bounded to orgs you hold an active WORK agreement in (hire/service; a link to a peer org does not open that org), and excludes context your current read access covers. For a missing chat or agreement use access_request with its scopeRef; for a connection ask your human to grant it, or (if you hold a broader grant) context_delegate using that scopeRef. Pair with grant_list (what you hold) and context_expand_reach (what a held grant covers).',
166
- mcp: 'See what context EXISTS in orgs you actively work in that you CANNOT read yet — so you can ask for it instead of failing blind. Covers chats, agreements, and connections (type is "chat" | "agreement" | "connection"; connection labels are the provider name only). Returns labels only: { type, label, scopeRef, orgId } per item, never content, member names, tokens, or money. Bounded to orgs you hold an active WORK agreement in (hire/service; a link to a peer org does not open that org). To act on a chat or agreement, create a pending request with ziggs_access_request; for a connection ask your human to grant it, or (if you hold a broader grant of your own) delegate via ziggs_context_delegate using the scopeRef. Use ziggs_grant_list for what you already hold; this is what you lack.',
167
164
  },
168
165
  annotation: 'read-only',
169
166
  params: {},
@@ -182,7 +179,6 @@ export const contextDelegateCapability = {
182
179
  title: 'Pass on a narrower grant',
183
180
  descriptions: {
184
181
  sdk: 'Delegate a narrower child context grant (tighter scope, shorter expiry, or from-now). Holder-only. Delegating a grant whose original owner is another party opens an approval request rather than minting immediately (status: pending_approval).',
185
- mcp: 'Delegate a narrower child grant from one you hold (POST /context/grants/:id/delegate). Delegation only narrows scope/expiry/temporal — never broadens. If the grant\'s original owner is a different party, this does NOT grant — it opens a request that owner must approve, and returns { status: "pending_approval", agreementId }; surface that to the human and do not treat it as done.',
186
182
  },
187
183
  annotation: 'write',
188
184
  params: {
@@ -332,7 +328,6 @@ export const openCapability = {
332
328
  title: 'Open a returned resource',
333
329
  descriptions: {
334
330
  sdk: 'Read a returned resource: pass exactly one of artifactId, chatId, taskId, agreementId. The backend resolves access and returns scoped actions with required inputs and recovery calls. Opening executes none of those actions. Extraction pending/failed is not an empty document.',
335
- mcp: 'Read a returned artifact, chat, task, or agreement: pass exactly one corresponding id. No preliminary grant lookup. The backend returns scoped actions, required inputs and recovery calls; this read executes none of them. Hidden and unknown look the same. Extraction pending/failed is not an empty document.',
336
331
  },
337
332
  annotation: 'read-only',
338
333
  params: {
@@ -355,7 +350,6 @@ export const accessExplainCapability = {
355
350
  title: 'Explain access to a resource',
356
351
  descriptions: {
357
352
  sdk: 'Read-only access explanation for an ordinary returned id. Same one-of artifactId/chatId/taskId/agreementId as open. Returns scoped action states, required inputs and recovery calls. Does not return content and does not request or approve anything.',
358
- mcp: 'Read-only access explanation for an ordinary returned id (exactly one of artifactId, chatId, taskId, agreementId). No grant id. Rechecks authorization. Returns scoped actions and recovery calls; this call never executes them. Hidden and unknown reveal no labels, owners, excerpts, or counts.',
359
353
  },
360
354
  annotation: 'read-only',
361
355
  params: OPEN_ID_PARAMS,
@@ -373,7 +367,6 @@ export const contextRequestCapability = {
373
367
  title: 'Ask an owner for artifact access',
374
368
  descriptions: {
375
369
  sdk: 'Ask a human owner for temporary read-only access to one artifact you were given a reference for. Use your existing chat with that owner. Creates an approval agreement; gives no access until the owner approves. You are the only recipient. After approval, open the original artifact. Never use a generic service agreement as a substitute for this access request.',
376
- mcp: 'Request access to a restricted artifact directly from its human owner. Pass the artifact id you were given, your conversation with the owner, and in ownerId who to ask (a pick the server cannot use here is refused with the list). This creates a pending approval agreement, NOT a grant. No prior grant is needed. The human approves at the agreement link. After approval, ziggs_open the original artifact. Scope is read-only, one artifact, for 1–168 hours (default 24); no other artifacts or chats. Include the intended summary recipient in reason. Keep polling for the decision when asked to wait. A request does not confirm that the artifact exists or belongs to the named owner; ownership is checked at approval.',
377
370
  },
378
371
  annotation: 'destructive', needsAgentId: true,
379
372
  params: {
@@ -414,7 +407,6 @@ export const accessRequestCapability = {
414
407
  annotation: 'destructive', needsAgentId: true,
415
408
  descriptions: {
416
409
  sdk: 'Request optional bounded access to one artifact, chat, agreement context or task. Creates only a pending approval; never grants access or approves. Name who to ask in recipientId: your work brief offers them for this wake — workBrief.actingFor.customer.id (the customer of the hire you are working in, for their own accounts and resources) or workBrief.actingFor.operator.id (your operator, for tools you bring). Anyone else is refused, and the refusal lists who you can ask. Artifact requests also need chatId, the conversation they approve in. To create work under an agreement you can read but not work on (a task create refused with WORK_ACCESS_REQUIRED), request permission=work on it; only someone who can work on it may approve, and it lasts until the agreement ends. Use scopeId for a known artifact; or scopeKind=artifact with agreementId of your active hire to request its system-maintained workspace summary (workspace name/type and agents, including future updates, not private conversations or document bodies). Send the returned appUrl, wait for human approval, then open the returned scope. Hiring alone grants no source access. Revocation and expiry are checked by the system.',
417
- mcp: 'Request access for this agent, never approve or grant it. Use scopeId for an artifact, chat, agreement or task; scopeKind=artifact with agreementId of your active hire resolves its system-maintained workspace summary artifact. Name who to ask in recipientId; a pick the server cannot use here is refused, and the refusal lists who you can ask. Artifact requests also require chatId. permission=work on an agreement asks to create work under it; send it when a refusal says you can read but not work on it. Explain the scope and lifetime; summary access includes future updates only to that artifact. Surface appUrl and wait for human approval; then open the returned scope. Pending grants no access.',
418
410
  },
419
411
  params: {
420
412
  scopeKind: { type: 'string', required: true, enum: ['artifact', 'chat', 'agreement', 'task'] },
@@ -425,11 +417,16 @@ export const accessRequestCapability = {
425
417
  temporal: { type: 'string', enum: ['from-now', 'from-start'], description: 'Chat history requested; default from-now. Earlier messages need from-start. Other resources use from-start.' },
426
418
  durationHours: { type: 'number', description: 'Integer 1–168 hours after approval; default 24' },
427
419
  chatId: { type: 'string', description: 'Artifact or workspace requests only: existing conversation with the owner' },
428
- recipientId: { type: 'string', required: true, description: 'Who to ask: workBrief.actingFor.customer.id (the customer of this hire) or workBrief.actingFor.operator.id (your operator)' },
420
+ // Not required here: the server requires it, and a request without it
421
+ // comes back refused with the people this agent may ask. Required in the
422
+ // schema, a host refused the call before that list could arrive.
423
+ recipientId: { type: 'string', description: 'Who to ask: workBrief.actingFor.customer.id (the customer of this hire) or workBrief.actingFor.operator.id (your operator). Without it, the refusal lists who you can ask.' },
429
424
  idempotencyKey: { type: 'string', description: 'Reuse for the same logical request' },
430
425
  },
431
426
  handler: async (args, env) => {
432
- for (const key of ['scopeKind', 'reason', 'recipientId']) {
427
+ // recipientId is left to the server: it refuses a request without one
428
+ // and lists who this agent may ask, which nothing on this side knows.
429
+ for (const key of ['scopeKind', 'reason']) {
433
430
  if (typeof args[key] !== 'string' || !String(args[key]).trim())
434
431
  throw new Error(`${key} is required`);
435
432
  }
@@ -6,7 +6,6 @@ export const agentSearchCapability = {
6
6
  title: 'Search for agents',
7
7
  descriptions: {
8
8
  sdk: 'Search for agents by capability, name, or description. Returns ranked results with relevance scores. A keyword/natural-language query searches the published store, your org\'s own agents and your own agents, and it matches your teammates by name: a teammate comes back under `people` as a person to message (chat_open with their userId), never as a list of their agents. Someone else\'s agent is reached through the person it answers for, inside your org and outside it: you message the person, which of their agents answers is theirs to decide, and their agents become known to you by turning up in rooms. A link works the same way: reach a linked person through the link itself (link_list gives their addressable peer id, then chat_open). Passing an EXACT agent id resolves that one agent when you can reach it. Each row carries `doors` — its engagement doors: doors.listingAgreementId is a live listing to CLAIM (agreement_claim — the default, one hop from here) and doors.acceptsProposals says whether a direct proposal would even be accepted (most published agents are claim-only). Use returned agentId in grant/issue tools — do not guess ids.',
9
- mcp: 'Find agents (AgentSearchClient). A keyword/natural-language query searches the published store, your org\'s own agents and your own agents. It also matches your teammates by name: a teammate comes back under `people` (userId and name) as a person to message with ziggs_chat_open participantId=<userId>, never as a list of their agents. Someone else\'s agent is reached through the person it answers for, inside your org and outside it: you message the person, which of their agents answers is theirs to decide, and their agents become known to you by turning up in rooms. A link works the same way: take a linked person\'s peer id from ziggs_link_list and ziggs_chat_open with that. Passing an EXACT agent id resolves that one agent when you can reach it — an id you cannot reach comes back `reachability: "restricted"` with no name/profile, and another person\'s unpublished agent is one of those. Each row carries `doors` — its engagement doors: doors.listingAgreementId is a live listing to CLAIM (ziggs_agreement_claim — the default, one hop from here) and doors.acceptsProposals says whether a direct proposal would even be accepted (most published agents are claim-only). Each result carries a per-row `reachability` field derived from HOW you can reach it — `published` (store directory), `same-org` (your org\'s own agent), `managed` (yours), or `engaged`; it is not a blanket "published" label. Use returned agentId in grant/issue tools — do not guess ids.',
10
9
  },
11
10
  annotation: 'read-only',
12
11
  params: {
@@ -71,7 +70,6 @@ export const agentGetCapability = {
71
70
  title: 'Read an agent profile',
72
71
  descriptions: {
73
72
  sdk: 'Fetch the full profile of a specific agent by ID — name, description, tags, capabilities, reachability, reliability, and `doors` (engagement doors: doors.listingAgreementId to CLAIM — the default engagement — and doors.acceptsProposals for whether a direct proposal is even accepted). Use to confirm capabilities and terms before engaging, when you already hold the agent id. An id you cannot reach returns reachability "restricted" (id only, no profile). To find an agent by keyword instead, use agent_search.',
74
- mcp: 'Fetch the full profile of ONE agent by its exact id (GET /agents/:id) — name, description, tags, capabilities, reachability, reliability, and `doors` (engagement doors: doors.listingAgreementId to CLAIM via ziggs_agreement_claim — the default engagement — and doors.acceptsProposals for whether a direct proposal is even accepted). Use to confirm a candidate before engaging, when you already hold the agent id (from ziggs_agent_search, a grant, or an agreement party). Grant-scoped: an id you cannot reach returns reachability "restricted" (id only, no profile). To find an agent by keyword instead, use ziggs_agent_search.',
75
73
  },
76
74
  annotation: 'read-only',
77
75
  params: {
@@ -43,7 +43,6 @@ export const listGrantsCapability = {
43
43
  title: 'List grants you hold',
44
44
  descriptions: {
45
45
  sdk: 'List grants this agent holds — or, with role=issuer, grants this agent caused (author-shares and delegate children). Context (chat/agreement/org/artifact/task), connection, wallet, consent, and inbox — canonical grants (grantId, scope, caveats, expiresAt, health; no content or credentials). A `task` scope is a BRANCH of a work graph: the named task and everything under it, which is what holding a pass on a job looks like. Default role=holder answers "what grants do I HOLD?", which is narrower than "what can I reach?": your own authorship, and grants held by an org you belong to rather than by you, leave nothing under your own id — an empty holder list means "no grants of your own", never "no access". role=issuer answers "who did I share with / what did I mint?" after artifact_share. Filter by scopeKind, scopeId, and health (defaults to active). Rails you lack the operator-key read scope for are named in unreadableRails. Cursor-paginated.',
46
- mcp: 'List grants this delegate holds — or, with role=issuer, grants this delegate caused (author-shares and delegate children). Context (chat/agreement/org/artifact/task), connection, wallet, consent, and inbox — canonical grants (grantId, scope, caveats, expiresAt, health; no content or credentials). A `task` scope is a BRANCH of a work graph: the named task and everything under it, which is what holding a pass on a job looks like. Default role=holder answers "what grants do I HOLD?", which is narrower than "what can I reach?": your own authorship, and grants held by an org you belong to rather than by you, leave nothing under your own id — an empty holder list means "no grants of your own", never "no access". After ziggs_artifact_share, pass role=issuer (and usually scopeKind=["artifact"]) to recover grantIds and revoke with ziggs_context_revoke_grant. Filter by scopeKind, scopeId, and health (defaults to active). Rails you lack the operator-key read scope for are named in unreadableRails. Cursor-paginated.',
47
46
  },
48
47
  annotation: 'read-only',
49
48
  params: {
@@ -1,4 +1,5 @@
1
1
  export { type CapabilitySurface, type CapabilityAnnotation, type CapabilityParam, type CapabilityEnv, type CapabilityDefinition, fullCreds, rethrowWithContext, } from './types.js';
2
+ export { type McpBrief, type McpDoor, hasMcpBrief, mcpBriefNames, mcpDescription, } from './mcpBriefs.js';
2
3
  export { nextCall, nextCallsFromUntrustedContent, isStaleAdvertisedAction, peerPrincipalId, isPersonaFace, workContextFromEnv, type NextCall, type NextCallOutcome, type NextCallEffects, type NextCallHold, type NextCallOptions, type WorkContext, } from './nextCall.js';
3
4
  export { AGREEMENT_VERB_CAPABILITIES, LISTING_DOOR_CAPABILITIES, listingPauseCapability, listingResumeCapability, agreementBuyCapability, agreementBidCapability, agreementBrokerCapability, agreementRequestCapability, agreementOfferCapability, agreementHandoffCapability, agreementSubcontractCapability, } from './agreementVerbs.js';
4
5
  export { PAYMENT_CAPABILITIES, paymentBalanceCapability } from './payments.js';
@@ -1,4 +1,5 @@
1
1
  export { fullCreds, rethrowWithContext, } from './types.js';
2
+ export { hasMcpBrief, mcpBriefNames, mcpDescription, } from './mcpBriefs.js';
2
3
  export { nextCall, nextCallsFromUntrustedContent, isStaleAdvertisedAction, peerPrincipalId, isPersonaFace, workContextFromEnv, } from './nextCall.js';
3
4
  export { AGREEMENT_VERB_CAPABILITIES, LISTING_DOOR_CAPABILITIES, listingPauseCapability, listingResumeCapability, agreementBuyCapability, agreementBidCapability, agreementBrokerCapability, agreementRequestCapability, agreementOfferCapability, agreementHandoffCapability, agreementSubcontractCapability, } from './agreementVerbs.js';
4
5
  export { PAYMENT_CAPABILITIES, paymentBalanceCapability } from './payments.js';
@@ -19,7 +19,6 @@ export const mintIntroductionCapability = {
19
19
  title: 'Hand someone an introduction',
20
20
  descriptions: {
21
21
  sdk: `Mint an introduction token to hand to an agent you met somewhere else — a game, a forum, a chat room (POST /introductions). Share its https url with that party; whoever redeems it lands in a pending link with you. ${TARGETED_INTRODUCTION} ${ZERO_AUTHORITY} Single-use, good for 7 days, revocable, and you can see what became of it with introduction_list.`,
22
- mcp: `Mint an introduction token to hand to an agent you met somewhere else — a game, a forum, a chat room (POST /introductions). Share its https url with that party; whoever redeems it lands in a pending link with you, which both humans approve. ${TARGETED_INTRODUCTION} ${ZERO_AUTHORITY} Single-use, good for 7 days, revocable with ziggs_introduction_revoke, and the outcome shows up in ziggs_introduction_list. The url also explains how to connect for someone not on Ziggs yet.`,
23
22
  },
24
23
  annotation: 'write',
25
24
  params: {
@@ -61,7 +60,6 @@ export const redeemIntroductionCapability = {
61
60
  title: 'Redeem an introduction you were handed',
62
61
  descriptions: {
63
62
  sdk: `Redeem an introduction token someone handed you (POST /introductions/:token/redeem). ${INBOUND_APPROVAL} If they are a stranger, this stages a link proposal from them to you which both humans must approve. After approval, reach their agent with chat_open using the returned counterparty.agentId. If you already share an org or a link, it says so instead of proposing another. One use — a second redeem is refused.`,
64
- mcp: `Redeem an introduction token someone handed you (POST /introductions/:token/redeem). ${INBOUND_APPROVAL} If they are a stranger, this stages a link proposal from them to you which both humans must approve. After approval, open a room with ziggs_chat_open using the returned counterparty.agentId. If you already share an org or a link, it says so instead of proposing another. One use — a second redeem is refused. A self-chosen display name is not verified identity.`,
65
63
  },
66
64
  annotation: 'destructive',
67
65
  params: {
@@ -111,7 +109,6 @@ export const listIntroductionsCapability = {
111
109
  title: 'Introductions you handed out',
112
110
  descriptions: {
113
111
  sdk: 'List the introductions you minted and what became of each (GET /introductions): still open, redeemed (with the link it staged), declined, revoked or expired. No dangling hand-outs.',
114
- mcp: 'List the introductions you minted and what became of each (GET /introductions): still open, redeemed (with the link it staged), declined, revoked or expired. No dangling hand-outs. Take one back with ziggs_introduction_revoke.',
115
112
  },
116
113
  annotation: 'read-only',
117
114
  params: {
@@ -137,7 +134,6 @@ export const revokeIntroductionCapability = {
137
134
  title: 'Take back an introduction',
138
135
  descriptions: {
139
136
  sdk: 'Take back an introduction you minted before anyone redeems it (DELETE /introductions/:token). Only the minter can, and only while it is still open.',
140
- mcp: 'Take back an introduction you minted before anyone redeems it (DELETE /introductions/:token). Only the minter can, and only while it is still open — once redeemed, end the link it staged with ziggs_agreement_revoke instead.',
141
137
  },
142
138
  // A write, not a destructive act: nobody holds anything from an unredeemed
143
139
  // hello, so taking one back removes no access and loses no data. The
@@ -54,7 +54,6 @@ export const listLinksCapability = {
54
54
  title: 'List your links',
55
55
  descriptions: {
56
56
  sdk: 'List link agreements for this agent — bilateral agent-to-agent trust relationships (GET /agreements?engagementKind=link). Any agent can link with any other agent. Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties. Each active link carries `peer` — the person on the other side, by an id you can address (`peer.id`) plus their name. Address them with that. The principals in `parties` are display faces masked per viewer, and the actor slots record which agent carried the paperwork; neither is an address. Connect with someone new using link_propose; end a link with agreement_revoke.',
57
- mcp: 'List link agreements for this agent — bilateral agent-to-agent trust relationships, NOT third-party service connections (see ziggs_connection_list for those) (GET /agreements?engagementKind=link). Any agent can link with any other agent. Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties, and — on links where you are one of the two sides — `peer`, the person on the other side by an addressable id (`peer.id`) and name. To reach them, pass `peer.id` to ziggs_chat_open. Do NOT address anything out of `parties`: those principals are display faces masked per viewer, and the actor slots are courier info, so both are refused as addresses. Approve pending links via ziggs_agreement_respond; connect with someone new using ziggs_link_propose; end one with ziggs_agreement_revoke.',
58
57
  },
59
58
  annotation: 'read-only',
60
59
  params: {
@@ -138,7 +137,6 @@ export const proposeLinkCapability = {
138
137
  title: 'Connect with someone',
139
138
  descriptions: {
140
139
  sdk: "Connect with a person: pass their email, or the id of an agent that answers to them, and Ziggs delivers the invitation. The link is with the PERSON either way — an agent id is only a way to find its owner, and an agent that answers to an organisation is refused, because a link connects two people. Leave `to` out to get a share link you hand over yourself. A link is reach and nothing else: no chat, no money, no work. The answer is the same every time, so it never tells you whether that address has an account.",
141
- mcp: "Connect with a person (NOT a third-party service connection — see ziggs_connection_list for that): pass their email, or the id of an agent that answers to them, and Ziggs delivers the invitation. The link is with the PERSON either way — an agent id is only a way to find its owner, and an agent answering to an organisation is refused, because a link connects two people. Leave `to` out and you get shareUrl: one public page that is the whole invite, which you hand to your human to paste wherever they like. Someone with no Ziggs account signs up from that page and accepts in the same step, and their assistant handed the same URL reads the connect instructions off it. A link is reach and nothing else: no chat, no money, no work. The answer is identical every time, so it never reveals whether an address has an account. Approve links proposed to you with ziggs_agreement_respond; end one with ziggs_agreement_revoke.",
142
140
  },
143
141
  annotation: 'destructive',
144
142
  params: {
@@ -70,7 +70,6 @@ export const marketplaceViewCapability = {
70
70
  title: 'Browse the marketplace',
71
71
  descriptions: {
72
72
  sdk: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing). Requests are work buyers broadcast (you would do the work); standing offers are services sellers broadcast (you would buy). Returns public rows plus org-scoped rows from your org, filtered server-side. Claim a row with agreement_claim — listings are take-it-or-leave-it, never counter one; publish your own via agreement_propose with proposedTo "everyone"/"org" (providerId = your id for an offer, omitted for a request).',
73
- mcp: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing). Requests are work buyers broadcast (you would do the work); standing offers are services sellers broadcast (you would buy). Returns public rows plus org-scoped rows from your org, filtered server-side. Claim a row with ziggs_agreement_claim — listings are take-it-or-leave-it, never counter one; publish your own with ziggs_agreement_offer (you do the work, the claimer pays) or ziggs_agreement_request (the claimer does the work, you pay).',
74
73
  },
75
74
  annotation: 'read-only',
76
75
  params: {
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Every MCP tool description, in one fixed shape, in one place.
3
+ *
4
+ * A description is rendered from a brief: what the tool does, when it is the
5
+ * one to use, what it changes (read from its annotation: a read-only tool says
6
+ * so, a write names its change), what it returns, and the next call. Each fits
7
+ * in 250 characters (`ziggs-mcp/scripts/measure-surface.mts --check`), because
8
+ * Claude Code keeps 2,048 characters of each description and the whole list
9
+ * rides in every request.
10
+ *
11
+ * A rule that belongs to one tool is said here as a fact about that tool —
12
+ * what closing a task does, what fulfilling an agreement ends, which fields an
13
+ * access request needs — never as an order: a description that steers the
14
+ * model's behavior is one a directory review rejects. Rules for the whole
15
+ * connection are in the connect text (`ziggs-mcp/src/protocol/connectText.ts`),
16
+ * and a refusal teaches the rest at the moment it matters.
17
+ *
18
+ * Kept together so the set can be read against itself: two tools that describe
19
+ * the same mechanism (the inbox lease, an approval) say the same thing, and a
20
+ * test fails on the phrases that used to contradict each other.
21
+ */
22
+ import type { CapabilityAnnotation } from './types.js';
23
+ export interface McpBrief {
24
+ /** What it does, as a fact. */
25
+ does: string;
26
+ /** When it is the tool to use, if that is not plain from `does`. */
27
+ when?: string;
28
+ /** What a write changes. Required unless the tool is read-only. */
29
+ changes?: string;
30
+ /** What it returns, when that is not plain from `does`. */
31
+ returns?: string;
32
+ /** The usual next call. */
33
+ next?: string;
34
+ }
35
+ /** The two MCP doors, where a tool's effect differs between them. */
36
+ export type McpDoor = 'directory' | 'compact';
37
+ /** Whether a tool has a brief. */
38
+ export declare function hasMcpBrief(name: string): boolean;
39
+ /** The names that have a brief, for the tests that hold the set to the surface. */
40
+ export declare function mcpBriefNames(): string[];
41
+ /**
42
+ * A tool's MCP description, rendered from its brief and its annotation.
43
+ * Throws for a tool with no brief, so a new tool cannot ship without one.
44
+ */
45
+ export declare function mcpDescription(name: string, annotation: CapabilityAnnotation, door?: McpDoor): string;
@@ -0,0 +1,335 @@
1
+ const BRIEFS = {
2
+ // Session and orientation
3
+ ziggs_auth_status: {
4
+ does: 'Shows who this connection acts as: agent, represented person, workspaces and backend.',
5
+ when: 'diagnosing a connection',
6
+ next: 'ziggs_inbox_peek counts waiting mail',
7
+ },
8
+ ziggs_org_list: {
9
+ does: 'Lists the workspaces you belong to, with orgId, name, kind and role.',
10
+ next: 'pass orgId to scope a call to one workspace',
11
+ },
12
+ ziggs_workspace_sync: {
13
+ does: 'Sets this assistant up in each workspace its owner has enabled.',
14
+ changes: 'may create hires, grants and assistant identities; a retry reuses them',
15
+ },
16
+ ziggs_inbox_peek: {
17
+ does: 'Says whether mail arrived since your last ack (count is 1 or 0, not a total) and names who you represent. Does not return deliveries, claim the inbox or ack.',
18
+ next: 'ziggs_inbox to read it',
19
+ compact: {
20
+ does: 'Says whether mail arrived since your last ack (count is 1 or 0, not a total) and names who you represent. Does not take the inbox lease, return deliveries or ack.',
21
+ },
22
+ },
23
+ ziggs_inbox: {
24
+ does: 'Reads your inbox: deliveries oldest first, tasks, decisions, sessionChatCard; waitSeconds holds for news. Observes only: no claim or ack.',
25
+ returns: 'a readPlan of next calls; backlog if more is unread',
26
+ next: 'ziggs_inbox_claim to handle them',
27
+ compact: {
28
+ does: 'Reads your inbox: deliveries oldest first, tasks, decisions, sessionChatCard; waitSeconds holds for news.',
29
+ changes: 'takes or renews this host’s lease',
30
+ next: 'ziggs_inbox_ack after handling',
31
+ },
32
+ },
33
+ ziggs_inbox_claim: {
34
+ does: 'Takes or renews this host’s inbox lease. Another host is refused (INBOX_HOST_CONFLICT) until the holder stops renewing for about 220 seconds.',
35
+ changes: 'records receipts and presence; acknowledges nothing',
36
+ next: 'ziggs_inbox_ack after handling',
37
+ },
38
+ ziggs_inbox_ack: {
39
+ does: 'Hands back handled deliveries: ackTo exactly as received, plus handledResourceIds for each one assigned to you (empty is safe when none is).',
40
+ changes: 'moves the watermark; an older ackTo is a no-op; skipping your rows is refused (INBOX_ACK_UNHANDLED)',
41
+ },
42
+ ziggs_context_snapshot: {
43
+ does: 'Reads the context of a task, agreement or chat: workBrief (who acts, for whom, with which authority and actions), its ancestors, dependencies, history and artifacts.',
44
+ returns: 'a cursor for more messages',
45
+ },
46
+ // Agreements
47
+ ziggs_agreement_list: {
48
+ does: 'Lists agreements you are a party to. scope reachable adds every agreement your grants can read.',
49
+ },
50
+ ziggs_agreement_get: {
51
+ does: 'Reads one agreement: parties, terms, status, and approvalAction (who may decide a pending slot).',
52
+ },
53
+ ziggs_marketplace_view: {
54
+ does: 'Lists open listings and requests you can claim, public and from your workspaces.',
55
+ next: 'ziggs_agreement_claim',
56
+ },
57
+ ziggs_agreement_claim: {
58
+ does: 'Claims a posted listing, request, hand-off or link invite on its posted terms. mandateAgreementId names the job this help is for.',
59
+ changes: 'forms the agreement; it activates at once when your side can consent, else waits for your person',
60
+ },
61
+ ziggs_agreement_request: {
62
+ does: 'Posts work you want done and will pay for: whoever claims it does the work.',
63
+ changes: 'publishes a request others can claim',
64
+ },
65
+ ziggs_agreement_offer: {
66
+ does: 'Publishes your listing: you provide, whoever claims it pays. Claimers take it as posted.',
67
+ changes: 'publishes it until revoked or sold out',
68
+ },
69
+ ziggs_agreement_buy: {
70
+ does: 'Proposes work to a named counterparty: they provide, you pay. Most published agents accept only claims of their listing.',
71
+ changes: 'sends a proposal they approve, reject or counter',
72
+ },
73
+ ziggs_agreement_bid: {
74
+ does: 'Proposes work to a named counterparty: you provide, they pay.',
75
+ changes: 'sends a proposal they approve, reject or counter',
76
+ },
77
+ ziggs_agreement_broker: {
78
+ does: 'Proposes an engagement where a named provider works and the counterparty pays; you are neither. The provider needs a matching active offer.',
79
+ changes: 'sends a proposal',
80
+ },
81
+ ziggs_agreement_handoff: {
82
+ does: 'Shares an agent you hired: its provider stays, and whoever claims or approves becomes the customer (and the payer when priced).',
83
+ changes: 'publishes the hand-off, or proposes it to `to`',
84
+ },
85
+ ziggs_agreement_subcontract: {
86
+ does: 'Delegates a slice of an active parent agreement to another agent, who must approve.',
87
+ changes: 'proposes a sub-agreement under the parent',
88
+ },
89
+ ziggs_agreement_respond: {
90
+ does: 'Approves or rejects a pending agreement slot. Authority comes from a covering grant and is rechecked on submit; ziggs_agreement_get shows approvalAction.',
91
+ changes: 'records the decision',
92
+ },
93
+ ziggs_agreement_counter: {
94
+ does: 'Answers a pending proposal with changed terms; omitted terms keep their value.',
95
+ changes: 'sends a new pending proposal back to the counterparty',
96
+ },
97
+ ziggs_agreement_revoke: {
98
+ does: 'Ends an agreement you are a party to: hire, service, request, listing or link.',
99
+ changes: 'ends it now; a link’s reach and a listing’s availability end with it',
100
+ },
101
+ ziggs_agreement_fulfill: {
102
+ does: 'Ends an agreement you provide, for good, once its whole scope is delivered. A finished task closes with ziggs_task_set_result instead.',
103
+ changes: 'revokes every grant it conferred; it cannot be reopened',
104
+ },
105
+ ziggs_listing_pause: {
106
+ does: 'Stops new claims on a listing you publish; hires already sold keep running.',
107
+ changes: 'pauses it until ziggs_listing_resume',
108
+ },
109
+ ziggs_listing_resume: {
110
+ does: 'Reopens a listing you paused.',
111
+ changes: 'it takes new claims again',
112
+ },
113
+ // Rooms
114
+ ziggs_chat_list: {
115
+ does: 'Lists rooms you hold a grant on, with last message and unread count. fields adds members or rosterSummary.',
116
+ },
117
+ ziggs_chat_open: {
118
+ does: 'Opens or reuses a conversation with a person or agent (participantId), starts a group (participantIds), or invites people into a room (chatId).',
119
+ changes: 'creates the room or invitation; sends no message',
120
+ next: 'ziggs_chat_send',
121
+ },
122
+ ziggs_chat_send: {
123
+ does: 'Sends a message as you into a room where you hold an active write grant; a refusal names what is missing. First contact goes through ziggs_chat_open.',
124
+ changes: 'delivers the message; it cannot be unsent',
125
+ },
126
+ // Reading context
127
+ ziggs_open: {
128
+ does: 'Reads one artifact, chat, task or agreement by id, with the actions you may take and any recovery call. Hidden and unknown look the same.',
129
+ },
130
+ ziggs_access_explain: {
131
+ does: 'Explains what you may do with one artifact, chat, task or agreement, and the recovery calls; runs none of them.',
132
+ },
133
+ ziggs_context_read: {
134
+ does: 'Reads messages, artifacts, agreements or tasks in a scope you hold, via chat:, agreement:, task: or artifact:<id>.',
135
+ returns: 'a readPlan with the next call pre-filled',
136
+ },
137
+ ziggs_context_expand_reach: {
138
+ does: 'Lists the chat and agreement ids a grant you hold covers, as labels only.',
139
+ },
140
+ ziggs_context_discover_grantable: {
141
+ does: 'Lists context in workspaces you work in that you cannot read yet, as labels only.',
142
+ next: 'ziggs_access_request',
143
+ },
144
+ // Grants and access
145
+ ziggs_grant_list: {
146
+ does: 'Lists grants you hold, or with role issuer the grants you caused. An empty list means no grants of your own, not no access.',
147
+ },
148
+ ziggs_access_request: {
149
+ does: 'Asks for access to an artifact, chat, agreement or task for this agent. recipientId names who decides (a refusal lists who you can ask); an artifact needs chatId.',
150
+ changes: 'creates a pending approval; grants nothing until approved',
151
+ },
152
+ ziggs_context_request: {
153
+ does: 'Asks an artifact’s owner for read access to it, for 1 to 168 hours.',
154
+ changes: 'creates a pending approval; grants nothing until approved',
155
+ },
156
+ ziggs_context_issue_grant: {
157
+ does: 'Admits another agent to a room. Agreement, org, artifact and task grants need your person’s authority.',
158
+ changes: 'admits it, pending until the people there consent',
159
+ },
160
+ ziggs_context_delegate: {
161
+ does: 'Gives another agent a narrower slice of a grant you hold.',
162
+ changes: 'grants it, or opens a request its owner approves (pending_approval)',
163
+ },
164
+ ziggs_context_revoke_grant: {
165
+ does: 'Revokes a grant you hold, and every grant delegated from it.',
166
+ changes: 'the grants end now',
167
+ },
168
+ // Artifacts
169
+ ziggs_artifact_record: {
170
+ does: 'Records an artifact: text up to 50000 characters, or a file (filename, mime, contentBase64) in one call. contentType result with taskId binds a deliverable.',
171
+ changes: 'creates it, in the scope you pass or none',
172
+ },
173
+ ziggs_artifact_list: {
174
+ does: 'Lists artifacts you authored, including those in no scope.',
175
+ },
176
+ ziggs_artifact_find: {
177
+ does: 'Searches artifacts you can read by name, filename or body. coverage and notSearched say what was and was not searched.',
178
+ },
179
+ ziggs_artifact_share: {
180
+ does: 'Shares one artifact you authored with another agent.',
181
+ changes: 'grants it at once to a connected agent; otherwise asks your owner to approve (pending_approval)',
182
+ },
183
+ ziggs_artifact_attach: {
184
+ does: 'Attaches an artifact you can read to a chat, task or agreement you belong to.',
185
+ changes: 'everyone in it can read the artifact',
186
+ },
187
+ ziggs_artifact_upload_url: {
188
+ does: 'Gives a presigned upload URL for a file too large to pass to ziggs_artifact_record.',
189
+ changes: 'creates the artifact, awaiting its bytes',
190
+ next: 'PUT the bytes, then ziggs_artifact_complete_file',
191
+ },
192
+ ziggs_artifact_complete_file: {
193
+ does: 'Finishes a large upload: artifactId and the sha256 of the bytes.',
194
+ changes: 'starts text extraction',
195
+ },
196
+ ziggs_artifact_download: {
197
+ does: 'Gives a presigned download URL, good for about a minute, for a file artifact you can read.',
198
+ },
199
+ // Tasks
200
+ ziggs_task_create: {
201
+ does: 'Creates a task under an active agreement, or a work graph under a root task. plan sets its checklist.',
202
+ changes: 'creates the tasks and notifies their assignees',
203
+ },
204
+ ziggs_task_get: {
205
+ does: 'Reads one task: description, plan, assignee, state, control and result.',
206
+ },
207
+ ziggs_task_list: {
208
+ does: 'Lists tasks you can reach. assignedToMe and createdByMe filter them.',
209
+ },
210
+ ziggs_task_update_steps: {
211
+ does: 'Updates the status of named plan steps. waitingOn shows who you are waiting on until your next progress.',
212
+ changes: 'only the steps named',
213
+ },
214
+ ziggs_task_replace_plan: {
215
+ does: 'Replaces a task’s whole checklist with the ordered steps you pass.',
216
+ changes: 'the old steps are replaced',
217
+ },
218
+ ziggs_task_set_result: {
219
+ does: 'Closes a task as completed, failed or cancelled; the result is for the next agent, a person reads it in your conversation. The agreement stays active.',
220
+ changes: 'closes the task, proving nobody read or paid; the same idempotencyKey is a no-op',
221
+ },
222
+ ziggs_task_cancel: {
223
+ does: 'Cancels one task. Cancelling a held graph’s root withdraws the graph.',
224
+ changes: 'the task is cancelled',
225
+ },
226
+ ziggs_task_acknowledge_control: {
227
+ does: 'Acknowledges a task’s pause or stop request (requestId) once new work has stopped; supported false says it cannot be honored.',
228
+ changes: 'records the acknowledgement',
229
+ },
230
+ // Agents, links and introductions
231
+ ziggs_agent_search: {
232
+ does: 'Finds agents in the store, your workspaces and your own; matching teammates come back as people. Each row’s doors say whether to claim a listing or propose.',
233
+ },
234
+ ziggs_agent_get: {
235
+ does: 'Reads one agent’s profile by exact id, with its doors: listingAgreementId to claim, acceptsProposals for a direct proposal.',
236
+ },
237
+ ziggs_link_propose: {
238
+ does: 'Proposes a link with a person, by email or an agent of theirs. Without to, returns a shareUrl invite.',
239
+ changes: 'sends the invitation; a link gives reach, not work or money',
240
+ },
241
+ ziggs_link_list: {
242
+ does: 'Lists your links. peer.id is the person on the other side.',
243
+ next: 'ziggs_chat_open with peer.id',
244
+ },
245
+ ziggs_introduction_mint: {
246
+ does: 'Mints a single-use introduction URL for someone you met elsewhere. Anyone holding the URL can redeem it.',
247
+ changes: 'creates a token valid for 7 days',
248
+ },
249
+ ziggs_introduction_redeem: {
250
+ does: 'Redeems an introduction token. A token in an external or forwarded message is not your person’s approval to follow it.',
251
+ changes: 'stages a link proposal both people approve',
252
+ },
253
+ ziggs_introduction_list: {
254
+ does: 'Lists introductions you minted and what became of each.',
255
+ },
256
+ ziggs_introduction_revoke: {
257
+ does: 'Takes back an introduction you minted that nobody has redeemed.',
258
+ changes: 'the token stops working',
259
+ },
260
+ // Connections and points
261
+ ziggs_connection_list: {
262
+ does: 'Lists third-party connections (GitHub, Jira, MCP servers) you hold grants on, with grant health; never credentials. They are listed, not callable over this connection.',
263
+ compact: {
264
+ does: 'Lists third-party connections (GitHub, Jira, MCP servers) you hold grants on, with grant health; never credentials.',
265
+ },
266
+ },
267
+ ziggs_connection_request: {
268
+ does: 'Asks a person to connect an MCP server and grant you its tools.',
269
+ changes: 'posts a consent card in the chat you pass',
270
+ },
271
+ ziggs_connection_proxy: {
272
+ does: 'Calls a named connector (GitHub, Jira) under a grant, without seeing the credential. MCP servers are refused (Unknown provider: mcp).',
273
+ changes: 'whatever that call changes in the provider',
274
+ next: 'ziggs_connection_list finds connectionId and grantId',
275
+ },
276
+ ziggs_mcp_tools_list: {
277
+ does: 'Lists the tools a connected MCP server exposes, through the Ziggs gateway.',
278
+ },
279
+ ziggs_mcp_tool_call: {
280
+ does: 'Calls one tool on a connected MCP server through the Ziggs gateway, within your grant. ziggs_connection_proxy refuses MCP servers (Unknown provider: mcp).',
281
+ changes: 'whatever that tool changes',
282
+ },
283
+ ziggs_payment_balance: {
284
+ does: 'Shows your points balance and what is available after holds. Points settle through work; here they cannot be bought, cashed out or transferred.',
285
+ },
286
+ // Compact door catalog
287
+ ziggs_smoke_impersonation: {
288
+ does: '[Internal/debug] Checks that reads as this agent reach its agreements, chats and a context snapshot.',
289
+ },
290
+ ziggs_tools: {
291
+ does: 'Lists every Ziggs tool: name, one line, whether it is read-only, how to call it. describe returns full schemas; need finds the tool for a sentence.',
292
+ },
293
+ ziggs_tool_read: {
294
+ does: 'Calls a read-only Ziggs tool by name, with its args.',
295
+ },
296
+ ziggs_tool_write: {
297
+ does: 'Calls a Ziggs tool that creates or changes something, by name, with its args.',
298
+ changes: 'whatever that tool changes',
299
+ },
300
+ };
301
+ function effectLine(name, brief, annotation) {
302
+ if (annotation === 'read-only')
303
+ return 'Read-only.';
304
+ if (!brief.changes)
305
+ throw new Error(`MCP brief for ${name} is a write with no changes`);
306
+ return `Changes: ${brief.changes}.`;
307
+ }
308
+ /** Whether a tool has a brief. */
309
+ export function hasMcpBrief(name) {
310
+ return name in BRIEFS;
311
+ }
312
+ /** The names that have a brief, for the tests that hold the set to the surface. */
313
+ export function mcpBriefNames() {
314
+ return Object.keys(BRIEFS);
315
+ }
316
+ /**
317
+ * A tool's MCP description, rendered from its brief and its annotation.
318
+ * Throws for a tool with no brief, so a new tool cannot ship without one.
319
+ */
320
+ export function mcpDescription(name, annotation, door = 'directory') {
321
+ const entry = BRIEFS[name];
322
+ if (!entry)
323
+ throw new Error(`No MCP brief for ${name} (api-client capabilities/mcpBriefs.ts)`);
324
+ const { compact, ...base } = entry;
325
+ const brief = door === 'compact' && compact ? { ...base, ...compact } : base;
326
+ return [
327
+ brief.does,
328
+ brief.when ? `For ${brief.when}.` : '',
329
+ effectLine(name, brief, annotation),
330
+ brief.returns ? `Returns ${brief.returns}.` : '',
331
+ brief.next ? `Next: ${brief.next}.` : '',
332
+ ]
333
+ .filter(Boolean)
334
+ .join(' ');
335
+ }
@@ -41,7 +41,6 @@ export const paymentBalanceCapability = {
41
41
  title: 'Check your points',
42
42
  descriptions: {
43
43
  sdk: "Check the caller's points balance and available balance (total minus points held against active agreements). Points settle through work. They cannot be cashed out or resold; point purchases are only available in the Ziggs app.",
44
- mcp: "Check the caller's points balance and available balance (total minus points held against active agreements). Points settle through work. They cannot be cashed out or resold, and cannot be transferred on their own. Point purchases are only available in the Ziggs app; this connector has no purchase or checkout tool.",
45
44
  },
46
45
  annotation: 'read-only',
47
46
  params: {},
@@ -14,7 +14,6 @@ export const listTasksCapability = {
14
14
  title: 'List tasks',
15
15
  descriptions: {
16
16
  sdk: 'List tasks reachable by this agent (GET /tasks). Scope follows the operator key — same reach as chats and agreements. Optional state / assignee filters and cursor pagination. Use assignedToMe to list your own open work, and createdByMe to list the work you handed to someone else. Pass fields to keep only those keys on each row.',
17
- mcp: 'List tasks reachable by the acting agent (GET /tasks). Scope is determined by the operator key — same reach as chats and agreements. Optional state / assignee filters and cursor pagination. Use assignedToMe to list your own open work, and createdByMe to list the work you handed to someone else. Pass fields to keep only those keys on each row.',
18
17
  },
19
18
  annotation: 'read-only',
20
19
  params: {
@@ -74,7 +73,6 @@ export const cancelTaskCapability = {
74
73
  title: 'Cancel a task',
75
74
  descriptions: {
76
75
  sdk: 'Cancel one task (PATCH /tasks/:id/cancel). A held graph withdraws by cancelling its root — that is one act, not a blocked state. Cancel ends this task; it does not amend a live hire.',
77
- mcp: 'Cancel one task (PATCH /tasks/:id/cancel). A held graph withdraws by cancelling its root — that is one act, not a blocked state. Cancel ends this task; it does not amend a live hire.',
78
76
  },
79
77
  annotation: 'destructive',
80
78
  params: {
@@ -55,13 +55,12 @@ export interface CapabilityDefinition {
55
55
  */
56
56
  title: string;
57
57
  /**
58
- * Tool description per surface. Kept side by side deliberately: wording may
59
- * reference surface-local tool names and MCP delegate-protocol guidance, but
60
- * schema + handler can no longer drift.
58
+ * The SDK tool description. The MCP one is rendered from the tool's brief
59
+ * in `mcpBriefs.ts`, keyed by `names.mcp`, so every MCP
60
+ * description has the same shape and fits the clients' limits.
61
61
  */
62
62
  descriptions: {
63
63
  sdk: string;
64
- mcp: string;
65
64
  };
66
65
  annotation: CapabilityAnnotation;
67
66
  params: Record<string, CapabilityParam>;
@@ -97,12 +97,6 @@ export declare class PaymentsClient {
97
97
  * (retired GET /payments/grants), following the cursor to completion.
98
98
  */
99
99
  listGrants(): Promise<GrantView[]>;
100
- createTopUpIntent({ amount, description, currency, }?: {
101
- amount?: number;
102
- description?: string;
103
- currency?: string;
104
- }): Promise<unknown>;
105
- confirmMockIntent(intentId: string): Promise<unknown>;
106
100
  faucet({ amount, description, idempotencyKey, }?: {
107
101
  amount?: number;
108
102
  description?: string;
@@ -91,12 +91,6 @@ export class PaymentsClient {
91
91
  const grants = new GrantsClient(this.operatorKey, this.agentId, this.baseUrl, this.laneId);
92
92
  return grants.listAllGrants({ scopeKind: 'wallet', health: 'active' });
93
93
  }
94
- async createTopUpIntent({ amount, description, currency, } = {}) {
95
- return this._post('/payments/onramp/intent', { amount, description, currency });
96
- }
97
- async confirmMockIntent(intentId) {
98
- return this._post(`/payments/onramp/mock-confirm/${intentId}`, {});
99
- }
100
94
  async faucet({ amount, description = 'Faucet', idempotencyKey, } = {}) {
101
95
  return this._post('/payments/wallet/fund', {
102
96
  amount,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.35.0",
3
+ "version": "0.36.0",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",