@ziggs-ai/ziggs-mcp 0.37.4 → 0.37.6

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.
package/README.md CHANGED
@@ -165,7 +165,6 @@ Startup validates the key shape, expiry (JWT `exp`), and agent resolution — er
165
165
  | `ziggs_artifact_download` | `GET /artifacts/:id/download` |
166
166
  | `ziggs_agent_search` | Agent search |
167
167
  | `ziggs_agent_get` | `GET /agents/:id` — full profile of one agent by exact id |
168
- | `ziggs_context_issue_grant` | Chat admission or `POST /context/grants` |
169
168
  | `ziggs_context_delegate` | `POST /context/grants/:id/delegate` |
170
169
  | `ziggs_context_revoke_grant` | `DELETE /context/grants/:id` |
171
170
  | `ziggs_link_propose` | `POST /agreements/links` — connect with someone by email or agent id, or mint a share link (claimUrl + paste text) |
@@ -15,7 +15,7 @@ ziggs_artifact_attach ziggs_artifact_upload_url ziggs_artifact_complete_file zig
15
15
  ziggs_task_create ziggs_task_set_result ziggs_task_replace_plan ziggs_task_update_steps
16
16
  ziggs_task_acknowledge_control ziggs_task_list ziggs_task_cancel ziggs_task_get
17
17
  ziggs_connection_list ziggs_agent_search ziggs_agent_get
18
- ziggs_context_issue_grant ziggs_context_delegate ziggs_context_request ziggs_access_request
18
+ ziggs_context_delegate ziggs_access_request
19
19
  ziggs_link_propose ziggs_link_list ziggs_introduction_mint ziggs_introduction_redeem
20
20
  ziggs_introduction_list ziggs_introduction_revoke ziggs_context_revoke_grant ziggs_payment_balance
21
21
  `.trim().split(/\s+/));
@@ -32,7 +32,7 @@ ziggs_agent_search ziggs_agent_get ziggs_marketplace_view
32
32
  ziggs_agreement_buy ziggs_agreement_bid ziggs_agreement_broker ziggs_agreement_request
33
33
  ziggs_agreement_handoff ziggs_agreement_claim ziggs_agreement_subcontract
34
34
  ziggs_chat_open ziggs_chat_send ziggs_artifact_share ziggs_artifact_attach
35
- ziggs_context_issue_grant ziggs_context_delegate ziggs_context_request ziggs_access_request
35
+ ziggs_context_delegate ziggs_access_request
36
36
  ziggs_link_propose ziggs_introduction_mint ziggs_introduction_redeem
37
37
  `.trim().split(/\s+/));
38
38
  export function installDirectorySurface(server) {
package/dist/server.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { type Creds } from '@ziggs-ai/api-client';
3
3
  import type { ZiggsMcpConfig } from './config.js';
4
+ export type { ZiggsMcpConfig };
4
5
  /** Shared MCP server factory — stdio (local) and remote HTTP (backend) reuse this. */
5
6
  export declare function createZiggsMcpServer(creds: Creds, cfg: ZiggsMcpConfig): McpServer;
6
7
  /** Drop this process's inbox host. Best-effort — shutdown must not fail on it. */
@@ -38,8 +38,7 @@ export const SEARCH_ALIASES = {
38
38
  'add people',
39
39
  ],
40
40
  ziggs_agent_search: ['teammate', 'colleague', 'directory', 'find person'],
41
- ziggs_access_request: ['access', 'permission', 'request access', 'chat', 'approval', 'grant'],
42
- ziggs_context_request: ['grant', 'permission', 'restricted', 'request access', 'unlock document'],
41
+ ziggs_access_request: ['access', 'permission', 'request access', 'chat', 'approval', 'grant', 'restricted', 'unlock document'],
43
42
  ziggs_agreement_claim: ['hire'],
44
43
  ziggs_agreement_buy: [
45
44
  'hire',
package/dist/tools.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { isDirectorySurface } from './directorySurface.js';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { z } from 'zod';
4
- import { presentResourceActions, getAgreement, getMyAgreements, listMyChats, respondToAgreement, revokeAgreement, counterAgreement, fulfillAgreement, sendChatMessage, ConnectionsClient, ContextReadClient, GrantsClient, InboxClient, createTask, updateTaskState, acknowledgeTaskControl, replaceTaskPlan, updateTaskPlanSteps, listTasks, getTask, getBackendUrl, fetchMyOrgs, fetchSessionAccess, isMcpOAuthDelegateSession, GRANTS_CAPABILITIES, AGREEMENT_VERB_CAPABILITIES, LISTING_DOOR_CAPABILITIES, CONTEXT_GRANT_SCOPE_KINDS, contextReadCapability, openCapability, accessExplainCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, recordArtifactCapability, listArtifactsCapability, findArtifactsCapability, shareArtifactCapability, attachArtifactCapability, uploadArtifactUrlCapability, completeArtifactFileCapability, downloadArtifactCapability, openConversationCapability, connectionProxyCapability, requestConnectionCapability, agreementClaimCapability, agreementSubcontractCapability, listTasksCapability, cancelTaskCapability, marketplaceViewCapability, parseListFields, pickListedRows, projectChatListRows, sessionOrientation, presentSendResult, presentTaskOutcome, explainRefusedRead, RESOURCE_HIDDEN_MESSAGE, } from '@ziggs-ai/api-client';
4
+ import { presentResourceActions, getAgreement, getMyAgreements, listMyChats, respondToAgreement, revokeAgreement, counterAgreement, fulfillAgreement, sendChatMessage, ConnectionsClient, ContextReadClient, GrantsClient, InboxClient, createTask, updateTaskState, acknowledgeTaskControl, replaceTaskPlan, updateTaskPlanSteps, listTasks, getTask, getBackendUrl, fetchMyOrgs, fetchSessionAccess, isMcpOAuthDelegateSession, GRANTS_CAPABILITIES, AGREEMENT_VERB_CAPABILITIES, LISTING_DOOR_CAPABILITIES, CONTEXT_GRANT_SCOPE_KINDS, contextReadCapability, openCapability, accessExplainCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, recordArtifactCapability, listArtifactsCapability, findArtifactsCapability, shareArtifactCapability, attachArtifactCapability, uploadArtifactUrlCapability, completeArtifactFileCapability, downloadArtifactCapability, openConversationCapability, connectionProxyCapability, requestConnectionCapability, agreementClaimCapability, agreementSubcontractCapability, listTasksCapability, cancelTaskCapability, marketplaceViewCapability, parseListFields, pickListedRows, projectChatListRows, sessionOrientation, presentSendResult, presentTaskOutcome, explainRefusedRead, RESOURCE_HIDDEN_MESSAGE, SOURCES_DESCRIPTION, } from '@ziggs-ai/api-client';
5
5
  import { decodeOperatorKeyClaims } from './operatorKey.js';
6
6
  import { registerTrustTools } from './trustTools.js';
7
7
  import { registerPaymentTools } from './paymentTools.js';
@@ -250,6 +250,15 @@ function isReadRefusal(e) {
250
250
  const status = e?.status;
251
251
  return status === 403 || status === 404;
252
252
  }
253
+ /**
254
+ * What a write drew on, as every write tool takes it. Loose on purpose, the
255
+ * shape the capability adapter gives an object list: the server checks each
256
+ * entry and says which one is wrong, and a full schema here would repeat that
257
+ * check on six tools in every session.
258
+ */
259
+ function sourcesField() {
260
+ return z.array(z.record(z.unknown())).optional().describe(SOURCES_DESCRIPTION);
261
+ }
253
262
  export function registerZiggsTools(server, creds, cfg) {
254
263
  // A refused get answers as open would: the server's one judgement of
255
264
  // hidden or unreadable, and for unreadable the request to make. When that
@@ -449,7 +458,8 @@ export function registerZiggsTools(server, creds, cfg) {
449
458
  .string()
450
459
  .optional()
451
460
  .describe('Retry-safe key. Reuse the SAME key when re-sending the SAME logical message (e.g. after a network error/timeout) so it is stored and delivered exactly once — the backend dedupes on chatId + messageId. Use a fresh key (or omit) for a genuinely new message.'),
452
- }, destructive('Send a chat message'), async ({ chatId, to, receiverId, text, entryType, idempotencyKey, conversationAgreementId, underAgreementId, taskId }) => {
461
+ sources: sourcesField(),
462
+ }, destructive('Send a chat message'), async ({ chatId, to, receiverId, text, entryType, idempotencyKey, conversationAgreementId, underAgreementId, taskId, sources }) => {
453
463
  try {
454
464
  const roomId = typeof chatId === 'string' ? chatId.trim() : '';
455
465
  const personId = typeof to === 'string' ? to.trim() : '';
@@ -475,6 +485,7 @@ export function registerZiggsTools(server, creds, cfg) {
475
485
  taskId,
476
486
  entryType: entryType ?? 'message',
477
487
  contentType: 'text',
488
+ ...(sources ? { sources: sources } : {}),
478
489
  }, creds);
479
490
  // `success: true` was the whole answer, and an agent that had just sent
480
491
  // an answer read it as delivered. The presenter names the destination
@@ -567,9 +578,13 @@ export function registerZiggsTools(server, creds, cfg) {
567
578
  .string()
568
579
  .optional()
569
580
  .describe('Revised task description for the spawned work'),
570
- }, destructive('Counter a proposal'), async ({ agreementId, ...counter }) => {
581
+ sources: sourcesField(),
582
+ }, destructive('Counter a proposal'), async ({ agreementId, sources, ...counter }) => {
571
583
  try {
572
- const agreement = await counterAgreement(agreementId, counter, creds);
584
+ const agreement = await counterAgreement(agreementId, {
585
+ ...counter,
586
+ ...(sources ? { sources: sources } : {}),
587
+ }, creds);
573
588
  return textResult({ status: 'countered', agreementId, agreement });
574
589
  }
575
590
  catch (e) {
@@ -865,6 +880,12 @@ export function registerZiggsTools(server, creds, cfg) {
865
880
  assigneeId: z.string().optional(),
866
881
  waitsOn: z.array(z.string()).optional(),
867
882
  joinKind: z.enum(['all', 'any']).optional(),
883
+ runIf: z
884
+ .string()
885
+ .min(1)
886
+ .max(500)
887
+ .optional()
888
+ .describe('A yes/no question over the results of the nodes this one waits on, such as "Does the review report at least one bug?". On yes the node runs; on no it is skipped, and nodes waiting on it go ahead. When the answer is unclear it waits for the buyer. Needs waitsOn.'),
868
889
  }))
869
890
  .min(1)
870
891
  .max(100),
@@ -872,7 +893,7 @@ export function registerZiggsTools(server, creds, cfg) {
872
893
  review: z.literal('before_execution').optional(),
873
894
  })
874
895
  .optional()
875
- .describe('Native atomic graph. waitsOn values name nodeId values in this payload; all nodes are created or none are. Root nodes receive graph inputArtifactIds. review holds every node until the root acknowledgement.'),
896
+ .describe('Native atomic graph. waitsOn values name nodeId values in this payload; all nodes are created or none are. Root nodes receive graph inputArtifactIds. review holds every node until the root acknowledgement. runIf makes a node conditional on what the nodes before it found.'),
876
897
  // POST /tasks and the SDK's task_create have always taken
877
898
  // these three; only this surface hid them, so an agent on MCP had to
878
899
  // create-then-replace_plan even when it already knew the steps.
@@ -929,9 +950,11 @@ export function registerZiggsTools(server, creds, cfg) {
929
950
  })
930
951
  .optional()
931
952
  .describe('How often the holder may remind, and how many times at most. Both halves are required together: a cadence with no budget is refused, because one reminder is one wake and a rule that never says stop is an open-ended loop. Omit entirely for a task nobody needs reminding about.'),
932
- }, write('Create a task'), async ({ agreementId, description, title, parentTaskId, assigneeId, inputArtifactIds, waitsOn, graph, plan, planReviewTiming, requireMidWorkPlanAck, dueAt, checkBack, }) => {
953
+ sources: sourcesField(),
954
+ }, write('Create a task'), async ({ agreementId, description, title, parentTaskId, assigneeId, inputArtifactIds, waitsOn, graph, plan, planReviewTiming, requireMidWorkPlanAck, dueAt, checkBack, sources, }) => {
933
955
  try {
934
956
  const task = await createTask({
957
+ ...(sources ? { sources: sources } : {}),
935
958
  agreementId,
936
959
  description,
937
960
  title,
@@ -954,7 +977,8 @@ export function registerZiggsTools(server, creds, cfg) {
954
977
  });
955
978
  registerStrictTool(server, 'ziggs_task_set_result', {
956
979
  taskId: z.string(),
957
- state: z.enum(['completed', 'failed', 'cancelled']),
980
+ // Cancelling has its own tool, ziggs_task_cancel.
981
+ state: z.enum(['completed', 'failed']),
958
982
  result: z
959
983
  .object({
960
984
  summary: z.string().optional(),
@@ -969,9 +993,15 @@ export function registerZiggsTools(server, creds, cfg) {
969
993
  .string()
970
994
  .optional()
971
995
  .describe('Optional dedup key: a redelivered transition with the same key no-ops (returns the task) instead of erroring on an already-terminal task. Derive it deterministically (e.g. from taskId + target state) so a crash-replay reproduces it.'),
972
- }, destructive('File a task result'), async ({ taskId, state, result, errorMessage, idempotencyKey }) => {
996
+ sources: sourcesField(),
997
+ }, destructive('File a task result'), async ({ taskId, state, result, errorMessage, idempotencyKey, sources }) => {
973
998
  try {
974
- const confirm = await updateTaskState(taskId, state, { result, errorMessage, idempotencyKey }, creds);
999
+ const confirm = await updateTaskState(taskId, state, {
1000
+ result,
1001
+ errorMessage,
1002
+ idempotencyKey,
1003
+ ...(sources ? { sources: sources } : {}),
1004
+ }, creds);
975
1005
  // The confirmation said `completed` and left delivery,
976
1006
  // metering and the agreement to be inferred from it. The presenter
977
1007
  // states each one from what the server reported, and stays silent about
@@ -1009,6 +1039,7 @@ export function registerZiggsTools(server, creds, cfg) {
1009
1039
  .unknown()
1010
1040
  .optional()
1011
1041
  .describe('Optional step output stored with this replace.'),
1042
+ sources: sourcesField(),
1012
1043
  }))
1013
1044
  .describe('Full replacement step list (ordered)'),
1014
1045
  }, destructive('Update a task plan'), async ({ taskId, steps }) => {
@@ -1032,6 +1063,7 @@ export function registerZiggsTools(server, creds, cfg) {
1032
1063
  .unknown()
1033
1064
  .optional()
1034
1065
  .describe('Optional step output stored with this patch.'),
1066
+ sources: sourcesField(),
1035
1067
  }))
1036
1068
  .optional()
1037
1069
  .describe('The steps that changed. Do not resend the rest of the plan. Omit it only when this call is nothing but a waitingOn.'),
@@ -3,6 +3,8 @@ import { type Creds } from '@ziggs-ai/api-client';
3
3
  import type { ZiggsMcpConfig } from './config.js';
4
4
  /** agent search + context grant management through MCP.
5
5
  * The SDK-twin tools (search/get, links, delegate) come from the shared
6
- * capability layer; only the human-authority grant tools (issue/revoke) stay
7
- * MCP-local. */
6
+ * capability layer; only revoking a grant stays MCP-local. Issuing one is a
7
+ * person's act (POST /context/grants takes a signed-in session), so there is
8
+ * no agent tool for it: an agent shares with artifact_share, a chat_open
9
+ * invite, or context_delegate. */
8
10
  export declare function registerTrustTools(server: McpServer, creds: Creds, cfg?: ZiggsMcpConfig): void;
@@ -1,103 +1,20 @@
1
1
  import { z } from 'zod';
2
- import { CONTEXT_GRANT_SCOPE_KINDS, ContextGrantsClient, addChatMember, contextBounds, resolveOrgScopeId, LINK_CAPABILITIES, INTRODUCTION_CAPABILITIES, DISCOVERY_CAPABILITIES, contextDelegateCapability, contextRequestCapability, accessRequestCapability, } from '@ziggs-ai/api-client';
3
- import { write, destructive } from './toolAnnotations.js';
2
+ import { ContextGrantsClient, LINK_CAPABILITIES, INTRODUCTION_CAPABILITIES, DISCOVERY_CAPABILITIES, contextDelegateCapability, accessRequestCapability, } from '@ziggs-ai/api-client';
3
+ import { destructive } from './toolAnnotations.js';
4
4
  import { registerStrictTool } from './strictParams.js';
5
5
  import { toolError } from './toolError.js';
6
6
  import { registerCapabilities, registerCapability, textResult } from './capabilityAdapter.js';
7
- // `artifact` is the narrowest context scope — one specific artifact, shared
8
- // without sharing any container it sits in. `task` is a branch of a work graph:
9
- // the named task and everything under it. Kept in step with the rail's own list
10
- // (`CONTEXT_GRANT_SCOPE_KINDS`) rather than written out again — a literal subset
11
- // still typechecks, which is how `task` was unaskable here after the server had
12
- // it.
13
- const grantScopeKindSchema = z.enum(CONTEXT_GRANT_SCOPE_KINDS);
14
- const contextTemporalSchema = z.enum(['from-now', 'from-start']);
15
7
  const DEFAULT_WEB_URL = 'https://ziggsai.com';
16
8
  /** agent search + context grant management through MCP.
17
9
  * The SDK-twin tools (search/get, links, delegate) come from the shared
18
- * capability layer; only the human-authority grant tools (issue/revoke) stay
19
- * MCP-local. */
10
+ * capability layer; only revoking a grant stays MCP-local. Issuing one is a
11
+ * person's act (POST /context/grants takes a signed-in session), so there is
12
+ * no agent tool for it: an agent shares with artifact_share, a chat_open
13
+ * invite, or context_delegate. */
20
14
  export function registerTrustTools(server, creds, cfg) {
21
15
  const webUrl = cfg?.ZIGGS_WEB_URL?.replace(/\/$/, '') ?? DEFAULT_WEB_URL;
22
16
  registerCapabilities(server, DISCOVERY_CAPABILITIES, creds);
23
- registerStrictTool(server, 'ziggs_context_issue_grant', {
24
- holderId: z.string().describe('Bare agent id receiving the grant'),
25
- scopeKind: grantScopeKindSchema,
26
- scopeId: z.string().describe('chatId, agreementId, orgId, artifactId, or taskId'),
27
- temporal: contextTemporalSchema
28
- .optional()
29
- .describe('from-now (default) or from-start (approval-gated on chat). Artifact ' +
30
- 'scope defaults to from-start and rejects from-now.'),
31
- expiresAt: z
32
- .string()
33
- .optional()
34
- .nullable()
35
- .describe('ISO-8601 expiry; omit for platform default TTL'),
36
- }, write('Give another agent access'), async ({ holderId, scopeKind, scopeId, temporal, expiresAt }) => {
37
- // An artifact predates any watermark you could set, so from-now would
38
- // validate and then read empty — the server refuses it outright. Defaulting
39
- // artifact scope to from-now here made the tool's own default invocation
40
- // fail, while the description promised it was always from-start. An
41
- // EXPLICIT from-now still goes through and is refused loudly: silently
42
- // rewriting what the caller asked for would hide the mistake.
43
- const resolvedTemporal = temporal ?? (scopeKind === 'artifact' ? 'from-start' : 'from-now');
44
- try {
45
- if (scopeKind === 'chat') {
46
- const result = await addChatMember({
47
- chatId: scopeId,
48
- memberId: holderId,
49
- memberType: 'agent',
50
- temporal: resolvedTemporal,
51
- }, creds);
52
- if ('status' in result && result.status === 'pending') {
53
- return textResult({
54
- status: 'pending_approval',
55
- outcome: 'pending',
56
- message: 'Human approval required before the grant is issued. Surface this to the user — do not treat as success.',
57
- scope: { kind: 'chat', id: scopeId },
58
- holderId,
59
- temporal: resolvedTemporal,
60
- pendingAdmission: result.pendingAdmission,
61
- });
62
- }
63
- return textResult({
64
- status: 'granted',
65
- scope: { kind: 'chat', id: scopeId },
66
- holderId,
67
- temporal: resolvedTemporal,
68
- bounds: {
69
- temporal: resolvedTemporal,
70
- note: 'from-now: readable content starts at grant watermark; from-start requires unanimous approval',
71
- },
72
- chat: 'chat' in result ? result.chat : undefined,
73
- });
74
- }
75
- // #6 — an org scope may be named rather than pasted as org_… id.
76
- let resolvedScopeId = scopeId;
77
- if (scopeKind === 'org') {
78
- resolvedScopeId = await resolveOrgScopeId({ creds, surface: 'mcp' }, scopeId);
79
- }
80
- const client = new ContextGrantsClient(creds.operatorKey, creds.agentId);
81
- const grant = await client.issueGrant({
82
- holderId,
83
- // This tool only ever hands access to another agent.
84
- holderKind: 'agent',
85
- scope: { kind: scopeKind, id: resolvedScopeId },
86
- temporal: resolvedTemporal,
87
- expiresAt,
88
- });
89
- return textResult({
90
- status: 'granted',
91
- grant,
92
- bounds: contextBounds(grant),
93
- });
94
- }
95
- catch (e) {
96
- return toolError(e);
97
- }
98
- });
99
17
  registerCapability(server, contextDelegateCapability, creds);
100
- registerCapability(server, contextRequestCapability, creds, { webUrl });
101
18
  registerCapability(server, accessRequestCapability, creds, { webUrl });
102
19
  if (!cfg?.coreOnly) {
103
20
  // #7 — the link tool group is skipped by the lean session-start
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/ziggs-mcp",
3
- "version": "0.37.4",
3
+ "version": "0.37.6",
4
4
  "description": "MCP server for Claude Code, Cursor, and other MCP hosts \u2014 act as your Ziggs delegate agent",
5
5
  "type": "module",
6
6
  "bin": {
@@ -47,7 +47,7 @@
47
47
  },
48
48
  "dependencies": {
49
49
  "@modelcontextprotocol/sdk": "^1.29.0",
50
- "@ziggs-ai/api-client": "0.37.4",
50
+ "@ziggs-ai/api-client": "0.37.6",
51
51
  "dotenv": "^16.6.1",
52
52
  "zod": "^3.24.2",
53
53
  "zod-to-json-schema": "^3.25.1"
@@ -85,8 +85,8 @@ See [references/inbox-rhythm.md](references/inbox-rhythm.md) for a full catch-up
85
85
  - **`ziggs_inbox`** (cold, no `waitSeconds`): at session start, if anything awaits approve/reject, show **`sessionChatCard`** (includes app links + exact respond commands). Do not auto-approve.
86
86
  - **`pending_approval`** (grants, admissions, from-start history, agreement steps): **stop and show the human** — do not auto-approve on their behalf unless they explicitly asked for that action in this session.
87
87
  - **`humanAttention` on inbox**: when present, **tell the human immediately** — list each pending agreement proposal and ask approve/reject before other work.
88
- - Before **`ziggs_context_issue_grant`**, **`ziggs_context_delegate`**, or any grant that exposes **existing** org/chat/agreement context: **ask the human** what scope and temporal bound they want (`from-now` vs `from-start`).
89
- - Trust tools (`ziggs_agent_search`, grant issue/delegate/revoke): use for cross-org collaboration only when the human’s goal requires it.
88
+ - Before **`ziggs_context_delegate`**, a **`ziggs_chat_open`** invite into an existing room, or any grant that exposes **existing** org/chat/agreement context: **ask the human** what scope and temporal bound they want (`from-now` vs `from-start`).
89
+ - Trust tools (`ziggs_agent_search`, grant delegate/revoke): use for cross-org collaboration only when the human’s goal requires it.
90
90
 
91
91
  See [references/grants-and-approvals.md](references/grants-and-approvals.md).
92
92
 
@@ -51,7 +51,7 @@ counterparty owner approves it, and unpublished delegates can then reach each ot
51
51
  3. Target human approves via **`ziggs_agreement_respond`** (action `approve`) when the
52
52
  pending link agreement shows in their inbox / `ziggs_link_list`. This is the same generic
53
53
  approval tool used for hire and service proposals — there is no separate link-response tool.
54
- 4. **`ziggs_chat_open`** with the person to talk; **`ziggs_context_issue_grant`** only to let them read your context.
54
+ 4. **`ziggs_chat_open`** with the person to talk. To let them read existing context: **`ziggs_artifact_share`** for one artifact, a **`ziggs_chat_open`** invite (chatId plus participantIds) for a room, or **`ziggs_context_delegate`** for a slice of a grant you hold.
55
55
  5. To read their context, they grant it or you ask with **`ziggs_access_request`**.
56
56
  6. `ziggs_context_revoke_grant` when context access should end; **`ziggs_agreement_revoke`** when
57
57
  the agreement should end — any kind: hire, service, request, offer, or link.
@@ -61,4 +61,4 @@ counterparty owner approves it, and unpublished delegates can then reach each ot
61
61
  ## Web UI (Settings → Connections)
62
62
 
63
63
  Confusingly named after the *other* "connection" (this is the agent-link handshake UI, not
64
- `ziggs_connection_proxy` third-party connections). After an agent link appears under **Connected**, use your Claude delegate (MCP) for **`ziggs_chat_open`** or **`ziggs_context_issue_grant`**. The web UI manages handshake only — not chat or context grants.
64
+ `ziggs_connection_proxy` third-party connections). After an agent link appears under **Connected**, use your Claude delegate (MCP) for **`ziggs_chat_open`**, **`ziggs_artifact_share`** or **`ziggs_context_delegate`**. The web UI manages handshake only — not chat or context grants.