@rigour-labs/mcp 2.18.0 → 2.18.2

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.
@@ -0,0 +1,51 @@
1
+ # Rigour Governance Skills
2
+
3
+ Rigour provides meta-cognitive governance tools to ensure AI agents stay aligned with engineering standards, project context, and brand identity during long-running coworking tasks.
4
+
5
+ ## Skills
6
+
7
+ ### `rigour_checkpoint`
8
+ Record a quality checkpoint during long-running agent execution. Use periodically (every 15-30 min) to enable drift detection and quality monitoring. Essential for coworking mode.
9
+
10
+ **Parameters:**
11
+ - `cwd` (string, required): Absolute path to the project root.
12
+ - `progressPct` (number, required): Estimated progress percentage (0-100).
13
+ - `summary` (string, required): Brief description of work done since last checkpoint.
14
+ - `qualityScore` (number, required): Self-assessed quality score (0-100).
15
+ - `filesChanged` (array of strings): List of files modified since last checkpoint.
16
+
17
+ ---
18
+
19
+ ### `rigour_agent_register`
20
+ Register an agent in a multi-agent session. Use this at the START of agent execution to claim task scope and enable cross-agent conflict detection.
21
+
22
+ **Parameters:**
23
+ - `cwd` (string, required): Absolute path to the project root.
24
+ - `agentId` (string, required): Unique identifier for this agent (e.g., 'marketing-pro', 'sales-bot').
25
+ - `taskScope` (array of strings, required): Glob patterns defining the files/directories this agent will work on.
26
+
27
+ ---
28
+
29
+ ### `rigour_check`
30
+ Run all configured quality gates (Lint, Test, AST, etc.) on the project. Call this before completing a task to verify overall quality.
31
+
32
+ **Parameters:**
33
+ - `cwd` (string, required): Absolute path to the project root.
34
+
35
+ ---
36
+
37
+ ### `rigour_get_fix_packet`
38
+ If gates fail, call this to retrieve a prioritized 'Fix Packet' containing detailed instructions on how to resolve the violations.
39
+
40
+ **Parameters:**
41
+ - `cwd` (string, required): Absolute path to the project root.
42
+
43
+ ---
44
+
45
+ ### `rigour_remember`
46
+ Persist critical instructions or project-specific conventions that should be remembered across sessions.
47
+
48
+ **Parameters:**
49
+ - `cwd` (string, required): Absolute path to the project root.
50
+ - `key` (string, required): Unique key for the memory.
51
+ - `value` (string, required): The instruction or context to remember.
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "Rigour Quality Governance",
3
+ "version": "2.14.0",
4
+ "description": "Meta-cognitive governance for AI agents. Monitor drift, manage agent teams, and enforce quality gates during long-running coworking tasks.",
5
+ "author": "Rigour Labs",
6
+ "capabilities": {
7
+ "mcp": {
8
+ "enabled": true
9
+ }
10
+ },
11
+ "entrypoint": "../dist/index.js",
12
+ "icon": "šŸ›”ļø",
13
+ "categories": [
14
+ "Productivity",
15
+ "Developer Tools"
16
+ ]
17
+ }
package/README.md CHANGED
@@ -24,6 +24,8 @@ Rigour moves code quality enforcement from the "Post-Commit" phase to the "In-Pr
24
24
 
25
25
  ## šŸ› ļø Available Tools
26
26
 
27
+ ### Core Tools
28
+
27
29
  | Tool | Description |
28
30
  |:---|:---|
29
31
  | `rigour_check` | Runs all configured quality gates on the current workspace. |
@@ -31,6 +33,19 @@ Rigour moves code quality enforcement from the "Post-Commit" phase to the "In-Pr
31
33
  | `rigour_check_pattern` | Checks if a proposed code pattern already exists in the codebase. |
32
34
  | `rigour_remember` | Stores project-specific context or rules in Rigour's persistent memory. |
33
35
  | `rigour_recall` | Retrieves stored context to guide AI generation. |
36
+ | `rigour_security_audit` | Runs a live CVE check on project dependencies. |
37
+
38
+ ### Frontier Model Tools (v2.14+)
39
+
40
+ For next-gen multi-agent workflows (Opus 4.6, GPT-5.3-Codex):
41
+
42
+ | Tool | Description |
43
+ |:---|:---|
44
+ | `rigour_agent_register` | Register agent in session with scope conflict detection. |
45
+ | `rigour_agent_deregister` | Remove agent from session when work is complete. |
46
+ | `rigour_checkpoint` | Record quality checkpoint with drift detection. |
47
+ | `rigour_handoff` | Initiate task handoff to another agent. |
48
+ | `rigour_handoff_accept` | Accept a pending handoff from another agent. |
34
49
 
35
50
  ---
36
51
 
package/dist/index.js CHANGED
@@ -299,6 +299,137 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
299
299
  },
300
300
  required: ["cwd", "command"],
301
301
  },
302
+ },
303
+ // === FRONTIER MODEL TOOLS (v2.14+) ===
304
+ // For Opus 4.6, GPT-5.3-Codex multi-agent and long-running sessions
305
+ {
306
+ name: "rigour_agent_register",
307
+ description: "Register an agent in a multi-agent session. Use this at the START of agent execution to claim task scope and enable cross-agent conflict detection. Required for Agent Team Governance.",
308
+ inputSchema: {
309
+ type: "object",
310
+ properties: {
311
+ cwd: {
312
+ type: "string",
313
+ description: "Absolute path to the project root.",
314
+ },
315
+ agentId: {
316
+ type: "string",
317
+ description: "Unique identifier for this agent (e.g., 'agent-a', 'opus-frontend').",
318
+ },
319
+ taskScope: {
320
+ type: "array",
321
+ items: { type: "string" },
322
+ description: "Glob patterns defining the files/directories this agent will work on (e.g., ['src/api/**', 'tests/api/**']).",
323
+ },
324
+ },
325
+ required: ["cwd", "agentId", "taskScope"],
326
+ },
327
+ },
328
+ {
329
+ name: "rigour_checkpoint",
330
+ description: "Record a quality checkpoint during long-running agent execution. Use periodically (every 15-30 min) to enable drift detection and quality monitoring. Essential for GPT-5.3 coworking mode.",
331
+ inputSchema: {
332
+ type: "object",
333
+ properties: {
334
+ cwd: {
335
+ type: "string",
336
+ description: "Absolute path to the project root.",
337
+ },
338
+ progressPct: {
339
+ type: "number",
340
+ description: "Estimated progress percentage (0-100).",
341
+ },
342
+ filesChanged: {
343
+ type: "array",
344
+ items: { type: "string" },
345
+ description: "List of files modified since last checkpoint.",
346
+ },
347
+ summary: {
348
+ type: "string",
349
+ description: "Brief description of work done since last checkpoint.",
350
+ },
351
+ qualityScore: {
352
+ type: "number",
353
+ description: "Self-assessed quality score (0-100). Be honest - artificially high scores trigger drift detection.",
354
+ },
355
+ },
356
+ required: ["cwd", "progressPct", "summary", "qualityScore"],
357
+ },
358
+ },
359
+ {
360
+ name: "rigour_handoff",
361
+ description: "Handoff task to another agent in a multi-agent workflow. Use when delegating a subtask or completing your scope. Enables verified handoff governance.",
362
+ inputSchema: {
363
+ type: "object",
364
+ properties: {
365
+ cwd: {
366
+ type: "string",
367
+ description: "Absolute path to the project root.",
368
+ },
369
+ fromAgentId: {
370
+ type: "string",
371
+ description: "ID of the agent initiating the handoff.",
372
+ },
373
+ toAgentId: {
374
+ type: "string",
375
+ description: "ID of the agent receiving the handoff.",
376
+ },
377
+ taskDescription: {
378
+ type: "string",
379
+ description: "Description of the task being handed off.",
380
+ },
381
+ filesInScope: {
382
+ type: "array",
383
+ items: { type: "string" },
384
+ description: "Files relevant to the handoff.",
385
+ },
386
+ context: {
387
+ type: "string",
388
+ description: "Additional context for the receiving agent.",
389
+ },
390
+ },
391
+ required: ["cwd", "fromAgentId", "toAgentId", "taskDescription"],
392
+ },
393
+ },
394
+ {
395
+ name: "rigour_agent_deregister",
396
+ description: "Deregister an agent from the multi-agent session. Use when an agent completes its work or needs to release its scope for another agent.",
397
+ inputSchema: {
398
+ type: "object",
399
+ properties: {
400
+ cwd: {
401
+ type: "string",
402
+ description: "Absolute path to the project root.",
403
+ },
404
+ agentId: {
405
+ type: "string",
406
+ description: "ID of the agent to deregister.",
407
+ },
408
+ },
409
+ required: ["cwd", "agentId"],
410
+ },
411
+ },
412
+ {
413
+ name: "rigour_handoff_accept",
414
+ description: "Accept a pending handoff from another agent. Use to formally acknowledge receipt of a task and verify you are the intended recipient.",
415
+ inputSchema: {
416
+ type: "object",
417
+ properties: {
418
+ cwd: {
419
+ type: "string",
420
+ description: "Absolute path to the project root.",
421
+ },
422
+ handoffId: {
423
+ type: "string",
424
+ description: "ID of the handoff to accept.",
425
+ },
426
+ agentId: {
427
+ type: "string",
428
+ description: "ID of the accepting agent (must match toAgentId in the handoff).",
429
+ },
430
+ },
431
+ required: ["cwd", "handoffId", "agentId"],
432
+ },
302
433
  }
303
434
  ],
304
435
  };
@@ -774,6 +905,255 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
774
905
  });
775
906
  break;
776
907
  }
908
+ // === FRONTIER MODEL TOOL HANDLERS (v2.14+) ===
909
+ case "rigour_agent_register": {
910
+ const { agentId, taskScope } = args;
911
+ // Load or create agent session
912
+ const sessionPath = path.join(cwd, '.rigour', 'agent-session.json');
913
+ let session = { agents: [], startedAt: new Date().toISOString() };
914
+ if (await fs.pathExists(sessionPath)) {
915
+ session = JSON.parse(await fs.readFile(sessionPath, 'utf-8'));
916
+ }
917
+ // Check for existing agent
918
+ const existingIdx = session.agents.findIndex((a) => a.agentId === agentId);
919
+ if (existingIdx >= 0) {
920
+ session.agents[existingIdx] = {
921
+ agentId,
922
+ taskScope,
923
+ registeredAt: session.agents[existingIdx].registeredAt,
924
+ lastCheckpoint: new Date().toISOString(),
925
+ };
926
+ }
927
+ else {
928
+ session.agents.push({
929
+ agentId,
930
+ taskScope,
931
+ registeredAt: new Date().toISOString(),
932
+ lastCheckpoint: new Date().toISOString(),
933
+ });
934
+ }
935
+ // Check for scope conflicts
936
+ const conflicts = [];
937
+ for (const agent of session.agents) {
938
+ if (agent.agentId !== agentId) {
939
+ for (const scope of taskScope) {
940
+ if (agent.taskScope.includes(scope)) {
941
+ conflicts.push(`${agent.agentId} also claims "${scope}"`);
942
+ }
943
+ }
944
+ }
945
+ }
946
+ await fs.ensureDir(path.join(cwd, '.rigour'));
947
+ await fs.writeFile(sessionPath, JSON.stringify(session, null, 2));
948
+ await logStudioEvent(cwd, {
949
+ type: "agent_registered",
950
+ requestId,
951
+ agentId,
952
+ taskScope,
953
+ conflicts,
954
+ });
955
+ let responseText = `āœ… AGENT REGISTERED: "${agentId}" claimed scope: ${taskScope.join(', ')}\n\n`;
956
+ responseText += `Active agents in session: ${session.agents.length}\n`;
957
+ if (conflicts.length > 0) {
958
+ responseText += `\nāš ļø SCOPE CONFLICTS DETECTED:\n${conflicts.map(c => ` - ${c}`).join('\n')}\n`;
959
+ responseText += `\nConsider coordinating with other agents or narrowing your scope.`;
960
+ }
961
+ result = {
962
+ content: [{ type: "text", text: responseText }],
963
+ };
964
+ break;
965
+ }
966
+ case "rigour_checkpoint": {
967
+ const { progressPct, filesChanged = [], summary, qualityScore } = args;
968
+ // Load checkpoint session
969
+ const checkpointPath = path.join(cwd, '.rigour', 'checkpoint-session.json');
970
+ let session = {
971
+ sessionId: `chk-session-${Date.now()}`,
972
+ startedAt: new Date().toISOString(),
973
+ checkpoints: [],
974
+ status: 'active'
975
+ };
976
+ if (await fs.pathExists(checkpointPath)) {
977
+ session = JSON.parse(await fs.readFile(checkpointPath, 'utf-8'));
978
+ }
979
+ const checkpointId = `cp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
980
+ const warnings = [];
981
+ // Quality threshold check
982
+ if (qualityScore < 80) {
983
+ warnings.push(`Quality score ${qualityScore}% is below threshold 80%`);
984
+ }
985
+ // Drift detection (quality degrading over time)
986
+ if (session.checkpoints.length >= 2) {
987
+ const recentScores = session.checkpoints.slice(-3).map((cp) => cp.qualityScore);
988
+ const avgRecent = recentScores.reduce((a, b) => a + b, 0) / recentScores.length;
989
+ if (qualityScore < avgRecent - 10) {
990
+ warnings.push(`Drift detected: quality dropped from avg ${avgRecent.toFixed(0)}% to ${qualityScore}%`);
991
+ }
992
+ }
993
+ const checkpoint = {
994
+ checkpointId,
995
+ timestamp: new Date().toISOString(),
996
+ progressPct,
997
+ filesChanged,
998
+ summary,
999
+ qualityScore,
1000
+ warnings,
1001
+ };
1002
+ session.checkpoints.push(checkpoint);
1003
+ await fs.ensureDir(path.join(cwd, '.rigour'));
1004
+ await fs.writeFile(checkpointPath, JSON.stringify(session, null, 2));
1005
+ await logStudioEvent(cwd, {
1006
+ type: "checkpoint_recorded",
1007
+ requestId,
1008
+ checkpointId,
1009
+ progressPct,
1010
+ qualityScore,
1011
+ warnings,
1012
+ });
1013
+ let responseText = `šŸ“ CHECKPOINT RECORDED: ${checkpointId}\n\n`;
1014
+ responseText += `Progress: ${progressPct}% | Quality: ${qualityScore}%\n`;
1015
+ responseText += `Summary: ${summary}\n`;
1016
+ responseText += `Total checkpoints: ${session.checkpoints.length}\n`;
1017
+ if (warnings.length > 0) {
1018
+ responseText += `\nāš ļø WARNINGS:\n${warnings.map(w => ` - ${w}`).join('\n')}\n`;
1019
+ if (qualityScore < 80) {
1020
+ responseText += `\nā›” QUALITY BELOW THRESHOLD: Consider pausing and reviewing recent work.`;
1021
+ }
1022
+ }
1023
+ const shouldContinue = qualityScore >= 80;
1024
+ result._shouldContinue = shouldContinue;
1025
+ result = {
1026
+ content: [{ type: "text", text: responseText }],
1027
+ };
1028
+ break;
1029
+ }
1030
+ case "rigour_handoff": {
1031
+ const { fromAgentId, toAgentId, taskDescription, filesInScope = [], context = '' } = args;
1032
+ const handoffId = `handoff-${Date.now()}`;
1033
+ const handoffPath = path.join(cwd, '.rigour', 'handoffs.jsonl');
1034
+ const handoff = {
1035
+ handoffId,
1036
+ timestamp: new Date().toISOString(),
1037
+ fromAgentId,
1038
+ toAgentId,
1039
+ taskDescription,
1040
+ filesInScope,
1041
+ context,
1042
+ status: 'pending',
1043
+ };
1044
+ await fs.ensureDir(path.join(cwd, '.rigour'));
1045
+ await fs.appendFile(handoffPath, JSON.stringify(handoff) + '\n');
1046
+ await logStudioEvent(cwd, {
1047
+ type: "handoff_initiated",
1048
+ requestId,
1049
+ handoffId,
1050
+ fromAgentId,
1051
+ toAgentId,
1052
+ taskDescription,
1053
+ });
1054
+ let responseText = `šŸ¤ HANDOFF INITIATED: ${handoffId}\n\n`;
1055
+ responseText += `From: ${fromAgentId} → To: ${toAgentId}\n`;
1056
+ responseText += `Task: ${taskDescription}\n`;
1057
+ if (filesInScope.length > 0) {
1058
+ responseText += `Files in scope: ${filesInScope.join(', ')}\n`;
1059
+ }
1060
+ if (context) {
1061
+ responseText += `Context: ${context}\n`;
1062
+ }
1063
+ responseText += `\nThe receiving agent should call rigour_agent_register to claim this scope.`;
1064
+ result = {
1065
+ content: [{ type: "text", text: responseText }],
1066
+ };
1067
+ break;
1068
+ }
1069
+ case "rigour_agent_deregister": {
1070
+ const { agentId } = args;
1071
+ const sessionPath = path.join(cwd, '.rigour', 'agent-session.json');
1072
+ if (!await fs.pathExists(sessionPath)) {
1073
+ result = {
1074
+ content: [{ type: "text", text: `āŒ No active agent session found.` }],
1075
+ };
1076
+ break;
1077
+ }
1078
+ const session = JSON.parse(await fs.readFile(sessionPath, 'utf-8'));
1079
+ const initialCount = session.agents.length;
1080
+ session.agents = session.agents.filter((a) => a.agentId !== agentId);
1081
+ if (session.agents.length === initialCount) {
1082
+ result = {
1083
+ content: [{ type: "text", text: `āŒ Agent "${agentId}" not found in session.` }],
1084
+ };
1085
+ break;
1086
+ }
1087
+ await fs.writeFile(sessionPath, JSON.stringify(session, null, 2));
1088
+ await logStudioEvent(cwd, {
1089
+ type: "agent_deregistered",
1090
+ requestId,
1091
+ agentId,
1092
+ remainingAgents: session.agents.length,
1093
+ });
1094
+ let responseText = `āœ… AGENT DEREGISTERED: "${agentId}" has been removed from the session.\n\n`;
1095
+ responseText += `Remaining agents: ${session.agents.length}\n`;
1096
+ if (session.agents.length > 0) {
1097
+ responseText += `Active: ${session.agents.map((a) => a.agentId).join(', ')}`;
1098
+ }
1099
+ result = {
1100
+ content: [{ type: "text", text: responseText }],
1101
+ };
1102
+ break;
1103
+ }
1104
+ case "rigour_handoff_accept": {
1105
+ const { handoffId, agentId } = args;
1106
+ const handoffPath = path.join(cwd, '.rigour', 'handoffs.jsonl');
1107
+ if (!await fs.pathExists(handoffPath)) {
1108
+ result = {
1109
+ content: [{ type: "text", text: `āŒ No handoffs found.` }],
1110
+ };
1111
+ break;
1112
+ }
1113
+ const content = await fs.readFile(handoffPath, 'utf-8');
1114
+ const handoffs = content.trim().split('\n').filter(l => l).map(line => JSON.parse(line));
1115
+ const handoff = handoffs.find((h) => h.handoffId === handoffId);
1116
+ if (!handoff) {
1117
+ result = {
1118
+ content: [{ type: "text", text: `āŒ Handoff "${handoffId}" not found.` }],
1119
+ };
1120
+ break;
1121
+ }
1122
+ if (handoff.toAgentId !== agentId) {
1123
+ result = {
1124
+ content: [{
1125
+ type: "text",
1126
+ text: `āŒ Agent "${agentId}" is not the intended recipient.\nHandoff is for: ${handoff.toAgentId}`
1127
+ }],
1128
+ isError: true
1129
+ };
1130
+ break;
1131
+ }
1132
+ handoff.status = 'accepted';
1133
+ handoff.acceptedAt = new Date().toISOString();
1134
+ handoff.acceptedBy = agentId;
1135
+ // Rewrite the file with updated handoff
1136
+ const updatedContent = handoffs.map((h) => JSON.stringify(h)).join('\n') + '\n';
1137
+ await fs.writeFile(handoffPath, updatedContent);
1138
+ await logStudioEvent(cwd, {
1139
+ type: "handoff_accepted",
1140
+ requestId,
1141
+ handoffId,
1142
+ acceptedBy: agentId,
1143
+ fromAgentId: handoff.fromAgentId,
1144
+ });
1145
+ let responseText = `āœ… HANDOFF ACCEPTED: ${handoffId}\n\n`;
1146
+ responseText += `From: ${handoff.fromAgentId}\n`;
1147
+ responseText += `Task: ${handoff.taskDescription}\n`;
1148
+ if (handoff.filesInScope?.length > 0) {
1149
+ responseText += `Files in scope: ${handoff.filesInScope.join(', ')}\n`;
1150
+ }
1151
+ responseText += `\nYou should now call rigour_agent_register to formally claim the scope.`;
1152
+ result = {
1153
+ content: [{ type: "text", text: responseText }],
1154
+ };
1155
+ break;
1156
+ }
777
1157
  default:
778
1158
  throw new Error(`Unknown tool: ${name}`);
779
1159
  }
@@ -0,0 +1 @@
1
+ export {};