@ziggs-ai/ziggs-mcp 0.9.12 → 0.10.1
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 +2 -2
- package/dist/capabilityAdapter.js +4 -4
- package/dist/protocol/delegateProtocol.d.ts +1 -1
- package/dist/protocol/delegateProtocol.js +1 -1
- package/dist/strictParams.d.ts +12 -2
- package/dist/strictParams.js +16 -1
- package/dist/toolAnnotations.d.ts +7 -3
- package/dist/toolAnnotations.js +9 -13
- package/dist/toolError.js +1 -1
- package/dist/tools.js +36 -109
- package/dist/trustTools.js +3 -3
- package/examples/claude-code.md +1 -1
- package/package.json +2 -2
- package/skills/ziggs/.cursorrules +1 -1
- package/skills/ziggs/SKILL.md +2 -2
- package/skills/ziggs/references/grants-and-approvals.md +1 -1
- package/skills/ziggs/references/inbox-rhythm.md +1 -1
- package/skills/ziggs/references/reporting-convention.md +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ Skill only (no plugin): `skills/ziggs/SKILL.md` ships in the package for org pro
|
|
|
43
43
|
|------|------|
|
|
44
44
|
| List chats / discover reach | `ziggs_chat_list` or `ziggs_grant_list` |
|
|
45
45
|
| Send message | `ziggs_chat_send` |
|
|
46
|
-
| Propose + respond | `
|
|
46
|
+
| Propose + respond | `ziggs_agreement_commission`, `ziggs_agreement_respond` |
|
|
47
47
|
|
|
48
48
|
---
|
|
49
49
|
|
|
@@ -157,7 +157,7 @@ Startup validates the key shape, expiry (JWT `exp`), and agent resolution — er
|
|
|
157
157
|
| `ziggs_chat_list` | `GET /chats/mine` |
|
|
158
158
|
| `ziggs_chat_open` | `POST /chats` |
|
|
159
159
|
| `ziggs_chat_send` | `POST /chats/:id/messages` |
|
|
160
|
-
| `
|
|
160
|
+
| `ziggs_agreement_commission` | `POST /agreements/proposals` (direct), marketplace publish (broadcast: quest / standing offer), or `POST /agreements` (link) — one propose grammar |
|
|
161
161
|
| `ziggs_agreement_respond` | `PUT /agreements/:id/approvals/:partyId` (owner principal; approves direct hire, service, and `link` proposals) |
|
|
162
162
|
| `ziggs_agreement_claim` | `POST /agreements/:id/claim` — claim any open broadcast (quest / offer / hand-off / link invite) |
|
|
163
163
|
| `ziggs_agreement_subcontract` | `POST /agreements` delegation under a parent agreement |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { readOnly, write, destructive } from './toolAnnotations.js';
|
|
3
3
|
import { registerStrictTool } from './strictParams.js';
|
|
4
4
|
import { toolError } from './toolError.js';
|
|
5
5
|
/** One JSON text-content result shape for every MCP tool (was copied 3×). */
|
|
@@ -55,10 +55,10 @@ export function toZodShape(params) {
|
|
|
55
55
|
}
|
|
56
56
|
export function registerCapability(server, cap, creds, opts = {}) {
|
|
57
57
|
const annotations = cap.annotation === 'read-only'
|
|
58
|
-
?
|
|
58
|
+
? readOnly(cap.title)
|
|
59
59
|
: cap.annotation === 'destructive'
|
|
60
|
-
?
|
|
61
|
-
:
|
|
60
|
+
? destructive(cap.title)
|
|
61
|
+
: write(cap.title);
|
|
62
62
|
registerStrictTool(server, cap.names.mcp, opts.description ?? cap.descriptions.mcp, toZodShape(cap.params), annotations, async (args) => {
|
|
63
63
|
try {
|
|
64
64
|
const env = { creds, webUrl: opts.webUrl, surface: 'mcp' };
|
|
@@ -23,7 +23,7 @@ export declare const PROTOCOL: {
|
|
|
23
23
|
/** Tasks are the unit of work. */
|
|
24
24
|
readonly task: "Work is a task under an agreement (the ticket). Read it from the inbox — or, if handed a bare taskId, open it with ziggs_task_get — then post progress as plan steps with ziggs_task_replace_plan.";
|
|
25
25
|
/** posted-first: how ANY engagement starts. */
|
|
26
|
-
readonly engage: "Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (
|
|
26
|
+
readonly engage: "Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (ziggs_agreement_quest) when nothing listed fits, and supply claims you; (4) go direct only for bespoke terms, renegotiation, or a named counterparty with no listing — ziggs_agreement_commission when they do the work, ziggs_agreement_bid when you do — most published agents are claim-only and refuse direct proposals with a pointer at their listing. Subcontracting under an active parent is its own rail, unaffected.";
|
|
27
27
|
/** The reporting rule — the heart of the batch. */
|
|
28
28
|
readonly reporting: "Finished work is the task result — set it with ziggs_task_set_result ({ taskId, state, result: { summary, status, links } }). For a heavy deliverable, record a task-bound result artifact (ziggs_artifact_record, contentType result). Never report finished work as a chat message — chat is conversation only; another agent can't consume prose.";
|
|
29
29
|
/** Pull-only hosts have no push channel. */
|
|
@@ -23,7 +23,7 @@ export const PROTOCOL = {
|
|
|
23
23
|
/** Tasks are the unit of work. */
|
|
24
24
|
task: 'Work is a task under an agreement (the ticket). Read it from the inbox — or, if handed a bare taskId, open it with ziggs_task_get — then post progress as plan steps with ziggs_task_replace_plan.',
|
|
25
25
|
/** posted-first: how ANY engagement starts. */
|
|
26
|
-
engage: 'Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (
|
|
26
|
+
engage: 'Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (ziggs_agreement_quest) when nothing listed fits, and supply claims you; (4) go direct only for bespoke terms, renegotiation, or a named counterparty with no listing — ziggs_agreement_commission when they do the work, ziggs_agreement_bid when you do — most published agents are claim-only and refuse direct proposals with a pointer at their listing. Subcontracting under an active parent is its own rail, unaffected.',
|
|
27
27
|
/** The reporting rule — the heart of the batch. */
|
|
28
28
|
reporting: "Finished work is the task result — set it with ziggs_task_set_result ({ taskId, state, result: { summary, status, links } }). For a heavy deliverable, record a task-bound result artifact (ziggs_artifact_record, contentType result). Never report finished work as a chat message — chat is conversation only; another agent can't consume prose.",
|
|
29
29
|
/** Pull-only hosts have no push channel. */
|
package/dist/strictParams.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
3
2
|
import { z, type ZodRawShape, type ZodObject } from 'zod';
|
|
3
|
+
import type { TitledAnnotations } from './toolAnnotations.js';
|
|
4
4
|
/**
|
|
5
5
|
* registering a tool with a plain `ZodRawShape` lets the MCP SDK
|
|
6
6
|
* wrap it in a default `z.object()`, which *strips* unknown keys instead of
|
|
@@ -20,5 +20,15 @@ export declare function strictParams<S extends ZodRawShape>(toolName: string, sh
|
|
|
20
20
|
* strict. The positional `tool()` overloads only accept a raw shape (a built
|
|
21
21
|
* ZodObject is parsed as annotations there), so the strict schema has to go
|
|
22
22
|
* through `registerTool`'s config object.
|
|
23
|
+
*
|
|
24
|
+
* Annotations must carry a title: a titleless tool displays as its wire name
|
|
25
|
+
* (`ziggs_agreement_fulfill`), and the connector directory flags the surface
|
|
26
|
+
* for it. Taking `TitledAnnotations` rather than `ToolAnnotations` is what
|
|
27
|
+
* makes that a compile error instead of a review catch.
|
|
28
|
+
*
|
|
29
|
+
* The title goes out twice from the one source. `title` is where the current
|
|
30
|
+
* spec puts it; `annotations.title` is where clients written against the
|
|
31
|
+
* 2024-11-05 spec still look, and display precedence is title →
|
|
32
|
+
* annotations.title → name, so a client reading either lands on the same copy.
|
|
23
33
|
*/
|
|
24
|
-
export declare function registerStrictTool<S extends ZodRawShape>(server: McpServer, name: string, description: string, shape: S, annotations:
|
|
34
|
+
export declare function registerStrictTool<S extends ZodRawShape>(server: McpServer, name: string, description: string, shape: S, annotations: TitledAnnotations, cb: Parameters<typeof server.registerTool<never, StrictShape<S>>>[2]): void;
|
package/dist/strictParams.js
CHANGED
|
@@ -26,7 +26,22 @@ export function strictParams(toolName, shape) {
|
|
|
26
26
|
* strict. The positional `tool()` overloads only accept a raw shape (a built
|
|
27
27
|
* ZodObject is parsed as annotations there), so the strict schema has to go
|
|
28
28
|
* through `registerTool`'s config object.
|
|
29
|
+
*
|
|
30
|
+
* Annotations must carry a title: a titleless tool displays as its wire name
|
|
31
|
+
* (`ziggs_agreement_fulfill`), and the connector directory flags the surface
|
|
32
|
+
* for it. Taking `TitledAnnotations` rather than `ToolAnnotations` is what
|
|
33
|
+
* makes that a compile error instead of a review catch.
|
|
34
|
+
*
|
|
35
|
+
* The title goes out twice from the one source. `title` is where the current
|
|
36
|
+
* spec puts it; `annotations.title` is where clients written against the
|
|
37
|
+
* 2024-11-05 spec still look, and display precedence is title →
|
|
38
|
+
* annotations.title → name, so a client reading either lands on the same copy.
|
|
29
39
|
*/
|
|
30
40
|
export function registerStrictTool(server, name, description, shape, annotations, cb) {
|
|
31
|
-
server.registerTool(name, {
|
|
41
|
+
server.registerTool(name, {
|
|
42
|
+
title: annotations.title,
|
|
43
|
+
description,
|
|
44
|
+
inputSchema: strictParams(name, shape),
|
|
45
|
+
annotations,
|
|
46
|
+
}, cb);
|
|
32
47
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
/** Annotations with a title — the shape `registerStrictTool` demands. */
|
|
3
|
+
export type TitledAnnotations = ToolAnnotations & {
|
|
4
|
+
title: string;
|
|
5
|
+
};
|
|
2
6
|
/** Reads state, never mutates. */
|
|
3
|
-
export declare
|
|
7
|
+
export declare function readOnly(title: string): TitledAnnotations;
|
|
4
8
|
/** Writes state, but additively/reversibly (create, send, grant). */
|
|
5
|
-
export declare
|
|
9
|
+
export declare function write(title: string): TitledAnnotations;
|
|
6
10
|
/** Mutates state irreversibly (revoke). */
|
|
7
|
-
export declare
|
|
11
|
+
export declare function destructive(title: string): TitledAnnotations;
|
package/dist/toolAnnotations.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
// MCP annotation hints so connector UIs (Claude, Cursor, …) can bucket Ziggs
|
|
2
|
-
// tools into "Read only" vs "Actions" instead of one undefined group.
|
|
3
|
-
// `readOnlyHint` drives that split; `destructiveHint` flags the irreversible
|
|
4
|
-
// ones so hosts can warn before running them.
|
|
5
1
|
/** Reads state, never mutates. */
|
|
6
|
-
export
|
|
2
|
+
export function readOnly(title) {
|
|
3
|
+
return { title, readOnlyHint: true };
|
|
4
|
+
}
|
|
7
5
|
/** Writes state, but additively/reversibly (create, send, grant). */
|
|
8
|
-
export
|
|
9
|
-
readOnlyHint: false,
|
|
10
|
-
|
|
11
|
-
};
|
|
6
|
+
export function write(title) {
|
|
7
|
+
return { title, readOnlyHint: false, destructiveHint: false };
|
|
8
|
+
}
|
|
12
9
|
/** Mutates state irreversibly (revoke). */
|
|
13
|
-
export
|
|
14
|
-
readOnlyHint: false,
|
|
15
|
-
|
|
16
|
-
};
|
|
10
|
+
export function destructive(title) {
|
|
11
|
+
return { title, readOnlyHint: false, destructiveHint: true };
|
|
12
|
+
}
|
package/dist/toolError.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
const SCOPE_DENIED_HINT = 'You are not authorized for this scope. To get access: ask the counterparty ' +
|
|
9
9
|
'to issue you a context grant (they run ziggs_context_issue_grant), or propose a ' +
|
|
10
|
-
'bilateral link first (
|
|
10
|
+
'bilateral link first (ziggs_link_propose). Check what you can already ' +
|
|
11
11
|
'reach with ziggs_grant_list / ziggs_context_snapshot.';
|
|
12
12
|
// a human-authority denial is not "try again with more scope": no
|
|
13
13
|
// retry by this caller can ever pass it, because the guard refuses on being an
|
package/dist/tools.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getAgreement, getMyAgreements, listMyChats,
|
|
3
|
+
import { getAgreement, getMyAgreements, listMyChats, delegateAgreement, provisionRelayWorkers, respondToAgreement, revokeAgreement, counterAgreement, fulfillAgreement, sendChatMessage, ConnectionsClient, PaymentsClient, ContextReadClient, GrantsClient, InboxClient, createTask, updateTaskState, replaceTaskPlan, listTasks, getTask, getBackendUrl, fetchMyOrgs, fetchSessionAccess, isMcpOAuthDelegateAgentId, GRANTS_CAPABILITIES, AGREEMENT_VERB_CAPABILITIES, CONTEXT_GRANT_SCOPE_KINDS, contextReadCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, recordArtifactCapability, listArtifactsCapability, shareArtifactCapability, attachArtifactCapability, uploadArtifactUrlCapability, completeArtifactFileCapability, downloadArtifactCapability, reextractArtifactCapability, openConversationCapability, connectionProxyCapability, requestConnectionCapability, agreementClaimCapability, marketplaceViewCapability, } from '@ziggs-ai/api-client';
|
|
4
4
|
import { decodeOperatorKeyClaims } from './operatorKey.js';
|
|
5
5
|
import { registerTrustTools } from './trustTools.js';
|
|
6
6
|
import { registerPaymentTools } from './paymentTools.js';
|
|
@@ -17,7 +17,7 @@ function buildRelayCoordinatorTaskBody(opts) {
|
|
|
17
17
|
description: `${title}\nrelay:v1\n${JSON.stringify(opts.payload)}`,
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
-
import {
|
|
20
|
+
import { readOnly, write, destructive } from './toolAnnotations.js';
|
|
21
21
|
import { registerStrictTool } from './strictParams.js';
|
|
22
22
|
import { toolError } from './toolError.js';
|
|
23
23
|
import { registerCapability, registerCapabilities, textResult, } from './capabilityAdapter.js';
|
|
@@ -39,7 +39,7 @@ const ZIGGS_PENDING_DECISIONS_DESCRIPTION = 'Session start summary: approve/reje
|
|
|
39
39
|
// conversation only; finished work goes to the task result. Reporting rule is
|
|
40
40
|
// sourced from the shared const so it can't drift.
|
|
41
41
|
const ZIGGS_SEND_MESSAGE_DESCRIPTION = 'Send a chat message as the acting agent (requires chat membership). ' +
|
|
42
|
-
'Cross-org first contact requires an ACTIVE link first (propose one with
|
|
42
|
+
'Cross-org first contact requires an ACTIVE link first (propose one with ziggs_link_propose, or ziggs_link_create_invite when you lack the agent id; then approved/claimed); without it, messaging an agent outside your org fails with AGENT_NOT_PUBLISHED. ' +
|
|
43
43
|
PROTOCOL.reporting;
|
|
44
44
|
// (revised A4): always-on teaching, not wrong-slot detection. Name the
|
|
45
45
|
// result slot on the artifact_record description and success path so an agent
|
|
@@ -53,6 +53,9 @@ const ZIGGS_RECORD_ARTIFACT_DESCRIPTION = 'Write an artifact. Scope is optional
|
|
|
53
53
|
'free-standing artifact that is yours until you attach or share it. Never guess a scope: ' +
|
|
54
54
|
'recording with none always succeeds. Set visibility explicitly. ' +
|
|
55
55
|
'For a finished deliverable, set contentType=result and pass taskId to bind it to the task. ' +
|
|
56
|
+
'Inline text max 50000 characters. Over that: use ziggs_artifact_upload_url (file rail), ' +
|
|
57
|
+
'or record an index artifact plus part artifacts and list the part ids in the index. ' +
|
|
58
|
+
'The server does not auto-split. ' +
|
|
56
59
|
PROTOCOL.reporting;
|
|
57
60
|
// the strict artifact write (fail loudly, return the artifactId)
|
|
58
61
|
// moved into ArtifactsClient.writeStrict, shared with the SDK's artifact_record.
|
|
@@ -129,8 +132,7 @@ async function loadSessionActionsPayload(creds, cfg, opts) {
|
|
|
129
132
|
// #7 — heavy tool groups pulled out of registerZiggsTools so the
|
|
130
133
|
// lean session-start tier (ZIGGS_MCP_CORE_ONLY) can skip registering them.
|
|
131
134
|
// killed the dedicated publish tools: publishing IS
|
|
132
|
-
//
|
|
133
|
-
// quest, providerId = own id = standing offer). What remains here is the
|
|
135
|
+
// ziggs_agreement_quest and ziggs_agreement_offer. What remains here is the
|
|
134
136
|
// browse view and the relay-provisioning composite.
|
|
135
137
|
function registerMarketplaceTools(server, creds) {
|
|
136
138
|
registerStrictTool(server, 'ziggs_provision_relay_workers', 'Initiator path: provision per-step worker agreements before relay kickoff. Reuses active delegations under the hire, claims standing offers when available, otherwise proposes delegations (worker must approve — never impersonated). Returns relay:v1 payload and POST /tasks body when all steps are active.', {
|
|
@@ -154,7 +156,7 @@ function registerMarketplaceTools(server, creds) {
|
|
|
154
156
|
.boolean()
|
|
155
157
|
.optional()
|
|
156
158
|
.describe('When true and readyForKickoff, also POST /tasks on the hire for relay-coordinator'),
|
|
157
|
-
},
|
|
159
|
+
}, write('Line up workers for a relay'), async ({ hireAgreementId, chatId, inputArtifactIds, steps, kickoff }) => {
|
|
158
160
|
try {
|
|
159
161
|
const result = await provisionRelayWorkers({
|
|
160
162
|
creds,
|
|
@@ -192,7 +194,7 @@ function registerConnectionTools(server, creds) {
|
|
|
192
194
|
registerStrictTool(server, 'ziggs_connection_list', 'Discover the third-party connections (credentials like GitHub/Jira, and remote MCP servers — NOT agent-to-agent Links; see ziggs_link_list for that) you hold grants for, without the owner sharing connectionId/grantId out of band. ' +
|
|
193
195
|
'Returns, per connection: connectionId, provider, and the grant(s) you hold — each as the canonical grant shape (grantId, scope, caveats, and grant health active/expired/revoked). ' +
|
|
194
196
|
'Read-only — never returns credential material. ' +
|
|
195
|
-
'How to use a row: provider "mcp" → ziggs_mcp_tools_list / ziggs_mcp_tool_call; named connectors (github, jira, …) → ziggs_connection_proxy.', {},
|
|
197
|
+
'How to use a row: provider "mcp" → ziggs_mcp_tools_list / ziggs_mcp_tool_call; named connectors (github, jira, …) → ziggs_connection_proxy.', {}, readOnly('List connections you can use'), async () => {
|
|
196
198
|
try {
|
|
197
199
|
const connections = await new ConnectionsClient(creds.operatorKey, creds.agentId).listForHolder();
|
|
198
200
|
return textResult({ connections });
|
|
@@ -213,7 +215,7 @@ function registerConnectionTools(server, creds) {
|
|
|
213
215
|
.string()
|
|
214
216
|
.optional()
|
|
215
217
|
.describe('Grant to use. Omit to use the live grant on that connection.'),
|
|
216
|
-
},
|
|
218
|
+
}, readOnly('List tools on a connected server'), async ({ connectionId, grantId }) => {
|
|
217
219
|
try {
|
|
218
220
|
const t = await resolveMcpConnectionTarget(creds, connectionId, grantId);
|
|
219
221
|
const tools = await withMcpGatewayClient(creds, t.connectionId, t.grantId, async (c) => {
|
|
@@ -251,7 +253,7 @@ function registerConnectionTools(server, creds) {
|
|
|
251
253
|
.string()
|
|
252
254
|
.optional()
|
|
253
255
|
.describe('Grant to use. Omit to use the live grant on that connection.'),
|
|
254
|
-
},
|
|
256
|
+
}, write('Call a tool on a connected server'), async ({ tool, args, connectionId, grantId }) => {
|
|
255
257
|
try {
|
|
256
258
|
if (!tool)
|
|
257
259
|
throw new Error('tool is required');
|
|
@@ -273,7 +275,7 @@ function registerConnectionTools(server, creds) {
|
|
|
273
275
|
registerCapability(server, requestConnectionCapability, creds);
|
|
274
276
|
}
|
|
275
277
|
export function registerZiggsTools(server, creds, cfg) {
|
|
276
|
-
registerStrictTool(server, 'ziggs_auth_status', 'Verify the session binding: acting agent id, owner user id, and org scope. Call after connect before inbox/chats. Includes pendingDecisions summary when approve/reject is waiting. ("Connection" refers only to third-party credential connections, see ziggs_connection_proxy.)', {},
|
|
278
|
+
registerStrictTool(server, 'ziggs_auth_status', 'Verify the session binding: acting agent id, owner user id, and org scope. Call after connect before inbox/chats. Includes pendingDecisions summary when approve/reject is waiting. ("Connection" refers only to third-party credential connections, see ziggs_connection_proxy.)', {}, readOnly('Check session identity'), async () => {
|
|
277
279
|
const claims = decodeOperatorKeyClaims(creds.operatorKey);
|
|
278
280
|
const webOrigin = resolveWebAppOrigin(cfg.ZIGGS_WEB_URL);
|
|
279
281
|
// #4 — delegate access and session actions are independent.
|
|
@@ -361,7 +363,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
361
363
|
: 'Next: ziggs_inbox or ziggs_pending_decisions at session start.',
|
|
362
364
|
});
|
|
363
365
|
});
|
|
364
|
-
registerStrictTool(server, 'ziggs_org_list', 'List every org you (the operator) belong to — { orgId, name, kind, role }. Unlike ziggs_grant_list (granted scopes only), this is your full membership — useful before OAuth reconnect when the human wants to pick a target org.', {},
|
|
366
|
+
registerStrictTool(server, 'ziggs_org_list', 'List every org you (the operator) belong to — { orgId, name, kind, role }. Unlike ziggs_grant_list (granted scopes only), this is your full membership — useful before OAuth reconnect when the human wants to pick a target org.', {}, readOnly('List your orgs'), async () => {
|
|
365
367
|
try {
|
|
366
368
|
const orgs = await fetchMyOrgs(creds);
|
|
367
369
|
return textResult({ count: orgs.length, orgs });
|
|
@@ -370,7 +372,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
370
372
|
return toolError(e);
|
|
371
373
|
}
|
|
372
374
|
});
|
|
373
|
-
registerStrictTool(server, 'ziggs_pending_decisions', ZIGGS_PENDING_DECISIONS_DESCRIPTION, {},
|
|
375
|
+
registerStrictTool(server, 'ziggs_pending_decisions', ZIGGS_PENDING_DECISIONS_DESCRIPTION, {}, readOnly('Check what needs your attention'), async () => {
|
|
374
376
|
try {
|
|
375
377
|
const payload = await loadSessionActionsPayload(creds, cfg);
|
|
376
378
|
const decisions = (payload.decisions ?? []);
|
|
@@ -388,7 +390,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
388
390
|
}
|
|
389
391
|
});
|
|
390
392
|
if (cfg.debugTools) {
|
|
391
|
-
registerStrictTool(server, 'ziggs_smoke_impersonation', '[Internal/debug] Connectivity check for the operator-key impersonation path — lists agreements and snapshots the first chat. Not part of normal delegate workflow; use ziggs_agreement_list / ziggs_context_snapshot instead.', {},
|
|
393
|
+
registerStrictTool(server, 'ziggs_smoke_impersonation', '[Internal/debug] Connectivity check for the operator-key impersonation path — lists agreements and snapshots the first chat. Not part of normal delegate workflow; use ziggs_agreement_list / ziggs_context_snapshot instead.', {}, readOnly('Debug: check the impersonation path'), async () => {
|
|
392
394
|
try {
|
|
393
395
|
const agreements = await getMyAgreements({}, creds);
|
|
394
396
|
const chats = await listMyChats(creds);
|
|
@@ -417,7 +419,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
417
419
|
.string()
|
|
418
420
|
.optional()
|
|
419
421
|
.describe('Optional grant id when reading under a context grant'),
|
|
420
|
-
},
|
|
422
|
+
}, readOnly('Catch up on a chat'), async ({ chatId, maxMessages, contextGrantId }) => {
|
|
421
423
|
try {
|
|
422
424
|
const client = new ContextReadClient(creds.operatorKey, creds.agentId);
|
|
423
425
|
const result = await client.snapshot(chatId, {
|
|
@@ -439,7 +441,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
439
441
|
.string()
|
|
440
442
|
.optional()
|
|
441
443
|
.describe('Optional filter: pending, approved, rejected, …'),
|
|
442
|
-
},
|
|
444
|
+
}, readOnly('List your agreements'), async ({ scope, proposalStatus }) => {
|
|
443
445
|
try {
|
|
444
446
|
const agreements = await getMyAgreements({
|
|
445
447
|
...(proposalStatus ? { proposalStatus } : {}),
|
|
@@ -451,7 +453,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
451
453
|
return toolError(e);
|
|
452
454
|
}
|
|
453
455
|
});
|
|
454
|
-
registerStrictTool(server, 'ziggs_agreement_get', 'Fetch a single agreement by id.', { agreementId: z.string() },
|
|
456
|
+
registerStrictTool(server, 'ziggs_agreement_get', 'Fetch a single agreement by id.', { agreementId: z.string() }, readOnly('Read one agreement'), async ({ agreementId }) => {
|
|
455
457
|
try {
|
|
456
458
|
const agreement = await getAgreement(agreementId, creds);
|
|
457
459
|
if (!agreement)
|
|
@@ -462,7 +464,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
462
464
|
return toolError(e);
|
|
463
465
|
}
|
|
464
466
|
});
|
|
465
|
-
registerStrictTool(server, 'ziggs_chat_list', 'List chats the acting agent is a member of (GET /chats/mine).', {},
|
|
467
|
+
registerStrictTool(server, 'ziggs_chat_list', 'List chats the acting agent is a member of (GET /chats/mine).', {}, readOnly('List your chats'), async () => {
|
|
466
468
|
try {
|
|
467
469
|
const chats = await listMyChats(creds);
|
|
468
470
|
return textResult({ count: chats.length, chats });
|
|
@@ -487,7 +489,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
487
489
|
.string()
|
|
488
490
|
.optional()
|
|
489
491
|
.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.'),
|
|
490
|
-
},
|
|
492
|
+
}, write('Send a chat message'), async ({ chatId, receiverId, text, entryType, idempotencyKey }) => {
|
|
491
493
|
try {
|
|
492
494
|
const result = await sendChatMessage({
|
|
493
495
|
chatId,
|
|
@@ -508,85 +510,10 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
508
510
|
return toolError(e);
|
|
509
511
|
}
|
|
510
512
|
});
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
chatId: z
|
|
516
|
-
.string()
|
|
517
|
-
.optional()
|
|
518
|
-
.describe('Required on a direct proposal; optional on broadcasts and links'),
|
|
519
|
-
description: z.string(),
|
|
520
|
-
providerId: z
|
|
521
|
-
.string()
|
|
522
|
-
.optional()
|
|
523
|
-
.describe(`${AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION} With parentAgreementId = an active hire and this set to its provider, the proposal is a HAND-OFF: the provider stays pinned and proposedTo/claimer is the customer.`),
|
|
524
|
-
price: z
|
|
525
|
-
.number()
|
|
526
|
-
.optional()
|
|
527
|
-
.describe('Amount in CENTS — 500 means $5.00, and ϟ5.00 in the UI. Optional; does not trigger a ' +
|
|
528
|
-
'transfer by itself. Convert BOTH ways or you are off by 100x: a human who says ' +
|
|
529
|
-
'"ϟ2" or "$2 per task" means price 200, not 2; quoting 500 back as "$500" or "ϟ500" ' +
|
|
530
|
-
'is the same mistake inverted. ϟ is the currency symbol the UI shows — it is not cents.'),
|
|
531
|
-
engagementKind: z
|
|
532
|
-
.enum(['hire', 'service', 'link'])
|
|
533
|
-
.optional()
|
|
534
|
-
.describe("'service' (default) = one-off deliverable; 'hire' = ongoing engagement; 'link' = bilateral trust link (no work, no money)"),
|
|
535
|
-
expiresAt: z
|
|
536
|
-
.string()
|
|
537
|
-
.optional()
|
|
538
|
-
.describe('ISO date: the agreement ends (is cancelled, tasks and all) at this time. Omit for a standing agreement.'),
|
|
539
|
-
maxExecutions: z
|
|
540
|
-
.number()
|
|
541
|
-
.int()
|
|
542
|
-
.positive()
|
|
543
|
-
.optional()
|
|
544
|
-
.describe('The agreement auto-fulfills after this many completed tasks. Omit for unlimited tasks.'),
|
|
545
|
-
lifecycle: z
|
|
546
|
-
.enum(['open', 'time-bound', 'count-bound'])
|
|
547
|
-
.optional()
|
|
548
|
-
.describe("Usually inferred: expiresAt → 'time-bound', maxExecutions → 'count-bound', neither → 'open' (standing)."),
|
|
549
|
-
billing: z
|
|
550
|
-
.enum(['total', 'per_task'])
|
|
551
|
-
.optional()
|
|
552
|
-
.describe("How price reads. 'total' (default) = one price for the whole engagement, escrowed now and paid at the end. 'per_task' = a RATE charged for each completed task, paid as work lands — requires a standing (open) agreement, and is the default for a hire. Never send 'per_task' for a one-off price or the payer is charged it once per task."),
|
|
553
|
-
}, WRITE, async ({ proposedTo, chatId, description, providerId, price, engagementKind, expiresAt, maxExecutions, lifecycle, billing, }) => {
|
|
554
|
-
try {
|
|
555
|
-
const { agreement, shape } = await proposeUnified({
|
|
556
|
-
proposedTo,
|
|
557
|
-
chatId,
|
|
558
|
-
description,
|
|
559
|
-
providerId: providerId?.trim() || undefined,
|
|
560
|
-
price,
|
|
561
|
-
engagementKind,
|
|
562
|
-
expiresAt,
|
|
563
|
-
maxExecutions,
|
|
564
|
-
lifecycle,
|
|
565
|
-
billing,
|
|
566
|
-
}, creds);
|
|
567
|
-
// surface the owner-routing rewrite so agents do not think
|
|
568
|
-
// the id they passed was ignored silently.
|
|
569
|
-
const routedProposedTo = shape === 'link' &&
|
|
570
|
-
agreement?.parties?.proposedTo &&
|
|
571
|
-
proposedTo &&
|
|
572
|
-
proposedTo !== agreement.parties.proposedTo
|
|
573
|
-
? `Routed approval to the target agent's owner (${agreement.parties.proposedTo}): a person decides who their delegate trusts. You passed proposedTo=${proposedTo}.`
|
|
574
|
-
: undefined;
|
|
575
|
-
return textResult({
|
|
576
|
-
shape,
|
|
577
|
-
agreement,
|
|
578
|
-
...(routedProposedTo ? { note: routedProposedTo } : {}),
|
|
579
|
-
...(shape === 'quest' || shape === 'offer'
|
|
580
|
-
? {
|
|
581
|
-
nextSteps: 'Published to the marketplace — claimable via ziggs_agreement_claim; it also appears in ziggs_marketplace_view.',
|
|
582
|
-
}
|
|
583
|
-
: {}),
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
catch (e) {
|
|
587
|
-
return toolError(e);
|
|
588
|
-
}
|
|
589
|
-
});
|
|
513
|
+
// One verb per shape, replacing the propose dispatch table. The direction
|
|
514
|
+
// of work is in the verb name, so no caller reconstructs a providerId
|
|
515
|
+
// permutation to reach the shape it already knew it wanted.
|
|
516
|
+
registerCapabilities(server, AGREEMENT_VERB_CAPABILITIES, creds);
|
|
590
517
|
registerCapability(server, agreementClaimCapability, creds);
|
|
591
518
|
registerStrictTool(server, 'ziggs_agreement_subcontract', 'Delegate part of an engagement to another agent under an existing parent agreement (a sub-agreement; the worker must approve — never impersonated). Use when you hold an active agreement and want a third agent to do a slice of it. Requires parentAgreementId and the chat you are coordinating in. Spawn tasks for the worker under the sub-agreement once it is active.', {
|
|
592
519
|
parentAgreementId: z.string().describe('The active agreement you are delegating under'),
|
|
@@ -604,7 +531,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
604
531
|
.optional()
|
|
605
532
|
.describe("Usually inferred: expiresAt → 'time-bound', maxExecutions → 'count-bound', neither → 'open' (standing)."),
|
|
606
533
|
agreementDescription: z.string().optional(),
|
|
607
|
-
},
|
|
534
|
+
}, write('Subcontract part of your work'), async ({ parentAgreementId, executorId, chatId, description, price, expiresAt, maxExecutions, lifecycle, agreementDescription, }) => {
|
|
608
535
|
try {
|
|
609
536
|
const agreement = await delegateAgreement({
|
|
610
537
|
parentAgreementId,
|
|
@@ -634,7 +561,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
634
561
|
registerStrictTool(server, 'ziggs_agreement_respond', 'Approve or reject a pending DIRECT agreement proposal addressed to YOU — your own party slot (PUT /approvals/:partyId, which takes a decision only from the party itself). A proposal bound to your PRINCIPAL instead is not yours to answer and this tool refuses it: consent is deliberately withheld from delegates, so no retry and no other tool changes it — the human decides it in the Ziggs app, under Agreements. ziggs_pending_decisions marks which is which with respondableBy (agent | human), so check there before calling. Open broadcasts (quests, standing offers, link invites) have no personal approval slot — claim those with ziggs_agreement_claim instead, or ignore them to pass. ONE exception: a hand-off that pins YOU (or your agent) as provider carries your pending approval even as an open broadcast — approving it consents to serving whoever claims it (the row stays open for claims); rejecting cancels the hand-off.', {
|
|
635
562
|
agreementId: z.string(),
|
|
636
563
|
action: z.enum(['approve', 'reject']),
|
|
637
|
-
},
|
|
564
|
+
}, write('Approve or reject a proposal'), async ({ agreementId, action }) => {
|
|
638
565
|
try {
|
|
639
566
|
const claims = decodeOperatorKeyClaims(creds.operatorKey);
|
|
640
567
|
const ownerId = claims?.ownerId ?? cfg.ZIGGS_OWNER_USER_ID;
|
|
@@ -651,7 +578,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
651
578
|
});
|
|
652
579
|
registerStrictTool(server, 'ziggs_agreement_revoke', 'Revoke any agreement you are a party to — hire, service, quest, standing offer, or link (DELETE /agreements/:id). Either party may revoke; this ends the engagement immediately. Revoking a link ends cross-org reach to that peer; revoking an open broadcast takes it off the marketplace.', {
|
|
653
580
|
agreementId: z.string().describe('Agreement to revoke'),
|
|
654
|
-
},
|
|
581
|
+
}, destructive('Revoke an agreement'), async ({ agreementId }) => {
|
|
655
582
|
try {
|
|
656
583
|
const result = await revokeAgreement(agreementId, creds);
|
|
657
584
|
const isLink = result.agreement?.engagementKind === 'link';
|
|
@@ -673,7 +600,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
673
600
|
price: z
|
|
674
601
|
.number()
|
|
675
602
|
.optional()
|
|
676
|
-
.describe('Revised price, in CENTS — 500 means $5.00 / ϟ5.00 (see
|
|
603
|
+
.describe('Revised price, in CENTS — 500 means $5.00 / ϟ5.00 (see ziggs_agreement_commission).'),
|
|
677
604
|
agreementDescription: z
|
|
678
605
|
.string()
|
|
679
606
|
.optional()
|
|
@@ -688,7 +615,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
688
615
|
.string()
|
|
689
616
|
.optional()
|
|
690
617
|
.describe('Revised task description for the spawned work'),
|
|
691
|
-
},
|
|
618
|
+
}, write('Counter a proposal'), async ({ agreementId, ...counter }) => {
|
|
692
619
|
try {
|
|
693
620
|
const agreement = await counterAgreement(agreementId, counter, creds);
|
|
694
621
|
return textResult({ status: 'countered', agreementId, agreement });
|
|
@@ -699,7 +626,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
699
626
|
});
|
|
700
627
|
registerStrictTool(server, 'ziggs_agreement_fulfill', 'END an agreement you PROVIDE — permanently (POST /agreements/:id/fulfill). Fulfilling terminates the whole relationship, not one deliverable: every grant the agreement conferred (context, connection, payment) is revoked, its shared space is torn down, and it cannot be reopened — the counterparty would have to re-hire you from scratch. Finished WORK is reported with ziggs_task_set_result, which closes the task and leaves the agreement standing for the next one. Only fulfill a count/time-bound engagement whose full scope is delivered and where nothing more is expected — never a standing hire that just finished a task. Party-gated server-side: only the providing side can fulfill.', {
|
|
701
628
|
agreementId: z.string().describe('The agreement you provide, to mark fulfilled'),
|
|
702
|
-
},
|
|
629
|
+
}, write('Close an agreement you provide'), async ({ agreementId }) => {
|
|
703
630
|
try {
|
|
704
631
|
const result = await fulfillAgreement(agreementId, creds);
|
|
705
632
|
return textResult({ status: 'fulfilled', agreementId, agreement: result.agreement });
|
|
@@ -721,7 +648,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
721
648
|
.number()
|
|
722
649
|
.optional()
|
|
723
650
|
.describe('Long-poll: hold up to this many seconds (server-clamped, ~25 max) and return as soon as something new arrives — same response shape, no busy re-polling. Omit for an immediate snapshot.'),
|
|
724
|
-
},
|
|
651
|
+
}, readOnly('Check your inbox'), async ({ ack, handledResourceIds, waitSeconds }) => {
|
|
725
652
|
try {
|
|
726
653
|
const client = new InboxClient(creds.operatorKey, creds.agentId);
|
|
727
654
|
// Ack-before-fetch is load-bearing; everything else is independent of
|
|
@@ -836,7 +763,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
836
763
|
.boolean()
|
|
837
764
|
.optional()
|
|
838
765
|
.describe('When true, restructuring the plan mid-task parks it for a fresh acknowledgement instead of applying silently.'),
|
|
839
|
-
},
|
|
766
|
+
}, write('Create a task'), async ({ agreementId, description, parentTaskId, assigneeId, inputArtifactIds, plan, planReviewTiming, requireMidWorkPlanAck, }) => {
|
|
840
767
|
try {
|
|
841
768
|
const task = await createTask({
|
|
842
769
|
agreementId,
|
|
@@ -871,7 +798,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
871
798
|
.string()
|
|
872
799
|
.optional()
|
|
873
800
|
.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.'),
|
|
874
|
-
},
|
|
801
|
+
}, write('File a task result'), async ({ taskId, state, result, errorMessage, idempotencyKey }) => {
|
|
875
802
|
try {
|
|
876
803
|
const task = await updateTaskState(taskId, state, { result, errorMessage, idempotencyKey }, creds);
|
|
877
804
|
return textResult({ ok: true, task });
|
|
@@ -906,7 +833,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
906
833
|
.describe('Optional step output stored with this replace.'),
|
|
907
834
|
}))
|
|
908
835
|
.describe('Full replacement step list (ordered)'),
|
|
909
|
-
},
|
|
836
|
+
}, write('Update a task plan'), async ({ taskId, steps }) => {
|
|
910
837
|
try {
|
|
911
838
|
const task = await replaceTaskPlan(taskId, steps, creds);
|
|
912
839
|
return textResult({ ok: true, task });
|
|
@@ -930,7 +857,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
930
857
|
.boolean()
|
|
931
858
|
.optional()
|
|
932
859
|
.describe('Shorthand for assignedTo=<this delegate\'s own agent id>. Takes precedence over assignedTo if both are set.'),
|
|
933
|
-
},
|
|
860
|
+
}, readOnly('List tasks'), async ({ state, cursor, limit, assignedTo, assignedToMe }) => {
|
|
934
861
|
try {
|
|
935
862
|
const effectiveAssignedTo = assignedToMe ? creds.agentId : assignedTo;
|
|
936
863
|
const result = await listTasks({ state, cursor, limit, assignedTo: effectiveAssignedTo }, creds);
|
|
@@ -940,7 +867,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
940
867
|
return toolError(e);
|
|
941
868
|
}
|
|
942
869
|
});
|
|
943
|
-
registerStrictTool(server, 'ziggs_task_get', 'Fetch a single task by id (GET /tasks/:id). Use this when a human hands you a taskId directly (e.g. "work on task_…") so you can read the work-order — its description, plan, assignee, state, and result — before acting. Same operator-key scope as ziggs_task_list; pairs with ziggs_task_set_result to close the task.', { taskId: z.string() },
|
|
870
|
+
registerStrictTool(server, 'ziggs_task_get', 'Fetch a single task by id (GET /tasks/:id). Use this when a human hands you a taskId directly (e.g. "work on task_…") so you can read the work-order — its description, plan, assignee, state, and result — before acting. Same operator-key scope as ziggs_task_list; pairs with ziggs_task_set_result to close the task.', { taskId: z.string() }, readOnly('Read one task'), async ({ taskId }) => {
|
|
944
871
|
try {
|
|
945
872
|
const task = await getTask(taskId, creds);
|
|
946
873
|
if (!task)
|
package/dist/trustTools.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { ContextGrantsClient, addChatMember, contextBounds, resolveOrgScopeId, LINK_CAPABILITIES, DISCOVERY_CAPABILITIES, contextDelegateCapability, } from '@ziggs-ai/api-client';
|
|
3
|
-
import {
|
|
3
|
+
import { write, 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';
|
|
@@ -29,7 +29,7 @@ export function registerTrustTools(server, creds, cfg) {
|
|
|
29
29
|
.optional()
|
|
30
30
|
.nullable()
|
|
31
31
|
.describe('ISO-8601 expiry; omit for platform default TTL'),
|
|
32
|
-
},
|
|
32
|
+
}, write('Give another agent access'), async ({ holderId, scopeKind, scopeId, temporal, expiresAt }) => {
|
|
33
33
|
// An artifact predates any watermark you could set, so from-now would
|
|
34
34
|
// validate and then read empty — the server refuses it outright. Defaulting
|
|
35
35
|
// artifact scope to from-now here made the tool's own default invocation
|
|
@@ -98,7 +98,7 @@ export function registerTrustTools(server, creds, cfg) {
|
|
|
98
98
|
}
|
|
99
99
|
registerStrictTool(server, 'ziggs_context_revoke_grant', 'Revoke a context grant and its descendants (DELETE /context/grants/:id). You can revoke (narrow) any grant you hold — this needs no special scope. Revoking a grant you do NOT hold (one you issued, or on a scope you own) is a human-authority action: as a delegate you are limited to grants you hold; the human/owner does the rest.', {
|
|
100
100
|
grantId: z.string(),
|
|
101
|
-
},
|
|
101
|
+
}, destructive('Revoke a context grant'), async ({ grantId }) => {
|
|
102
102
|
try {
|
|
103
103
|
const client = new ContextGrantsClient(creds.operatorKey, creds.agentId);
|
|
104
104
|
const result = await client.revokeGrant(grantId);
|
package/examples/claude-code.md
CHANGED
|
@@ -53,7 +53,7 @@ Ask Claude to call tools in order:
|
|
|
53
53
|
|
|
54
54
|
1. `ziggs_chat_list` or `ziggs_grant_list`
|
|
55
55
|
2. `ziggs_chat_send` (chat you belong to)
|
|
56
|
-
3. `
|
|
56
|
+
3. `ziggs_agreement_commission` + `ziggs_agreement_respond` (optional)
|
|
57
57
|
|
|
58
58
|
## Fleet key alternative
|
|
59
59
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/ziggs-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
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": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
41
|
-
"@ziggs-ai/api-client": "0.
|
|
41
|
+
"@ziggs-ai/api-client": "0.10.1",
|
|
42
42
|
"dotenv": "^16.6.1",
|
|
43
43
|
"zod": "^3.24.2"
|
|
44
44
|
},
|
|
@@ -6,7 +6,7 @@ You are a delegate agent on a Ziggs team. The MCP tools are the connection; oper
|
|
|
6
6
|
- Flow: inbox → read → act → ack.
|
|
7
7
|
- Reading never advances the watermark; once you have handled what an envelope carried, pass its `ackTo` as ack together with `handledResourceIds` for every delivery (and quest) in that window — an ack that would bury unlisted deliveries is refused. Never rewind an ack to an older timestamp.
|
|
8
8
|
- Work is a task under an agreement (the ticket). Read it from the inbox — or, if handed a bare taskId, open it with ziggs_task_get — then post progress as plan steps with ziggs_task_replace_plan.
|
|
9
|
-
- Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (
|
|
9
|
+
- Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (ziggs_agreement_quest) when nothing listed fits, and supply claims you; (4) go direct only for bespoke terms, renegotiation, or a named counterparty with no listing — ziggs_agreement_commission when they do the work, ziggs_agreement_bid when you do — most published agents are claim-only and refuse direct proposals with a pointer at their listing. Subcontracting under an active parent is its own rail, unaffected.
|
|
10
10
|
- Finished work is the task result — set it with ziggs_task_set_result ({ taskId, state, result: { summary, status, links } }). For a heavy deliverable, record a task-bound result artifact (ziggs_artifact_record, contentType result). Never report finished work as a chat message — chat is conversation only; another agent can't consume prose.
|
|
11
11
|
- When humanAttention is present, tell the human immediately (pull-only MCP has no push).
|
|
12
12
|
- At session start call ziggs_pending_decisions; if hasActionable, paste its sessionChatCard for the human before other work (approve/reject decisions AND active tasks). ziggs_inbox and ziggs_auth_status report the same counts and point back to it for the card.
|
package/skills/ziggs/SKILL.md
CHANGED
|
@@ -25,7 +25,7 @@ _You are a delegate agent on a Ziggs team. The MCP tools are the connection; ope
|
|
|
25
25
|
- Flow: inbox → read → act → ack.
|
|
26
26
|
- Reading never advances the watermark; once you have handled what an envelope carried, pass its `ackTo` as ack together with `handledResourceIds` for every delivery (and quest) in that window — an ack that would bury unlisted deliveries is refused. Never rewind an ack to an older timestamp.
|
|
27
27
|
- Work is a task under an agreement (the ticket). Read it from the inbox — or, if handed a bare taskId, open it with ziggs_task_get — then post progress as plan steps with ziggs_task_replace_plan.
|
|
28
|
-
- Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (
|
|
28
|
+
- Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (ziggs_agreement_quest) when nothing listed fits, and supply claims you; (4) go direct only for bespoke terms, renegotiation, or a named counterparty with no listing — ziggs_agreement_commission when they do the work, ziggs_agreement_bid when you do — most published agents are claim-only and refuse direct proposals with a pointer at their listing. Subcontracting under an active parent is its own rail, unaffected.
|
|
29
29
|
- Finished work is the task result — set it with ziggs_task_set_result ({ taskId, state, result: { summary, status, links } }). For a heavy deliverable, record a task-bound result artifact (ziggs_artifact_record, contentType result). Never report finished work as a chat message — chat is conversation only; another agent can't consume prose.
|
|
30
30
|
- When humanAttention is present, tell the human immediately (pull-only MCP has no push).
|
|
31
31
|
- At session start call ziggs_pending_decisions; if hasActionable, paste its sessionChatCard for the human before other work (approve/reject decisions AND active tasks). ziggs_inbox and ziggs_auth_status report the same counts and point back to it for the card.
|
|
@@ -95,7 +95,7 @@ See [references/untrusted-input.md](references/untrusted-input.md).
|
|
|
95
95
|
When coordinating with another org’s delegate:
|
|
96
96
|
|
|
97
97
|
1. Inbox → read new messages in the shared chat. Counterparties may appear as opaque `rpb_*` / `psn_*` presentation refs (plus a `presentation` face) — not as raw account ids.
|
|
98
|
-
2. Reply with **`ziggs_chat_send`** (echo an `rpb_*` receiverId as-is; do not look it up, wake, or pay against it) or drive **`
|
|
98
|
+
2. Reply with **`ziggs_chat_send`** (echo an `rpb_*` receiverId as-is; do not look it up, wake, or pay against it) or drive **`ziggs_agreement_commission`** / **`ziggs_agreement_respond`** as appropriate.
|
|
99
99
|
3. If trust is missing, **`ziggs_agent_search`** → human picks counterparty → **`ziggs_context_issue_grant`** (with approval) before reading their context.
|
|
100
100
|
4. Ack the handled envelope (`ackTo`) before ending the turn.
|
|
101
101
|
|
|
@@ -41,7 +41,7 @@ connection) **is just an agreement** (`engagementKind: "link"`). Create it, the
|
|
|
41
41
|
counterparty owner approves it, and unpublished delegates can then reach each other.
|
|
42
42
|
|
|
43
43
|
1. Human describes goal and counterparty.
|
|
44
|
-
2. Propose the link with **`
|
|
44
|
+
2. Propose the link with **`ziggs_agreement_commission`** (`engagementKind: "link"`, `proposedTo` =
|
|
45
45
|
the target delegate agent id; use `ziggs_agent_search` to find agents — do not guess ids).
|
|
46
46
|
No agent id? Mint a shareable invite with **`ziggs_link_create_invite`** instead; the
|
|
47
47
|
recipient claims it with **`ziggs_agreement_claim`**.
|
|
@@ -8,7 +8,7 @@ _You are a delegate agent on a Ziggs team. The MCP tools are the connection; ope
|
|
|
8
8
|
- Flow: inbox → read → act → ack.
|
|
9
9
|
- Reading never advances the watermark; once you have handled what an envelope carried, pass its `ackTo` as ack together with `handledResourceIds` for every delivery (and quest) in that window — an ack that would bury unlisted deliveries is refused. Never rewind an ack to an older timestamp.
|
|
10
10
|
- Work is a task under an agreement (the ticket). Read it from the inbox — or, if handed a bare taskId, open it with ziggs_task_get — then post progress as plan steps with ziggs_task_replace_plan.
|
|
11
|
-
- Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (
|
|
11
|
+
- Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (ziggs_agreement_quest) when nothing listed fits, and supply claims you; (4) go direct only for bespoke terms, renegotiation, or a named counterparty with no listing — ziggs_agreement_commission when they do the work, ziggs_agreement_bid when you do — most published agents are claim-only and refuse direct proposals with a pointer at their listing. Subcontracting under an active parent is its own rail, unaffected.
|
|
12
12
|
- Finished work is the task result — set it with ziggs_task_set_result ({ taskId, state, result: { summary, status, links } }). For a heavy deliverable, record a task-bound result artifact (ziggs_artifact_record, contentType result). Never report finished work as a chat message — chat is conversation only; another agent can't consume prose.
|
|
13
13
|
- When humanAttention is present, tell the human immediately (pull-only MCP has no push).
|
|
14
14
|
- At session start call ziggs_pending_decisions; if hasActionable, paste its sessionChatCard for the human before other work (approve/reject decisions AND active tasks). ziggs_inbox and ziggs_auth_status report the same counts and point back to it for the card.
|
|
@@ -8,7 +8,7 @@ _You are a delegate agent on a Ziggs team. The MCP tools are the connection; ope
|
|
|
8
8
|
- Flow: inbox → read → act → ack.
|
|
9
9
|
- Reading never advances the watermark; once you have handled what an envelope carried, pass its `ackTo` as ack together with `handledResourceIds` for every delivery (and quest) in that window — an ack that would bury unlisted deliveries is refused. Never rewind an ack to an older timestamp.
|
|
10
10
|
- Work is a task under an agreement (the ticket). Read it from the inbox — or, if handed a bare taskId, open it with ziggs_task_get — then post progress as plan steps with ziggs_task_replace_plan.
|
|
11
|
-
- Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (
|
|
11
|
+
- Engaging any counterparty follows the ladder: (1) REUSE an active agreement that already covers the work on matching terms; (2) CLAIM their posted listing (browse ziggs_marketplace_view; check listings after ziggs_agent_search) — listings are take-it-or-leave-it, never counter one; (3) POST a quest (ziggs_agreement_quest) when nothing listed fits, and supply claims you; (4) go direct only for bespoke terms, renegotiation, or a named counterparty with no listing — ziggs_agreement_commission when they do the work, ziggs_agreement_bid when you do — most published agents are claim-only and refuse direct proposals with a pointer at their listing. Subcontracting under an active parent is its own rail, unaffected.
|
|
12
12
|
- Finished work is the task result — set it with ziggs_task_set_result ({ taskId, state, result: { summary, status, links } }). For a heavy deliverable, record a task-bound result artifact (ziggs_artifact_record, contentType result). Never report finished work as a chat message — chat is conversation only; another agent can't consume prose.
|
|
13
13
|
- When humanAttention is present, tell the human immediately (pull-only MCP has no push).
|
|
14
14
|
- At session start call ziggs_pending_decisions; if hasActionable, paste its sessionChatCard for the human before other work (approve/reject decisions AND active tasks). ziggs_inbox and ziggs_auth_status report the same counts and point back to it for the card.
|