pluribus-context 0.3.40 → 0.3.42
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/CHANGELOG.md +8 -0
- package/README.md +3 -2
- package/bin/pluribus.js +3 -1
- package/docs/.nojekyll +0 -0
- package/docs/.well-known/agent-skills/context-receipts/SKILL.md +206 -0
- package/docs/.well-known/agent-skills/index.json +19 -0
- package/docs/.well-known/agent-skills/skill-policy-receipts/SKILL.md +77 -0
- package/docs/agent-surface-proof-chain.md +176 -0
- package/docs/cursor-claude-context-handoff.md +68 -0
- package/docs/index.html +38 -0
- package/docs/receipt-playground.html +304 -0
- package/docs/session-preflight-receipts.md +77 -0
- package/examples/claude-md-read-receipts/README.md +70 -0
- package/examples/claude-md-read-receipts/check-read-receipt.mjs +119 -0
- package/examples/claude-md-read-receipts/sample-read-receipt.json +45 -0
- package/examples/claude-md-read-receipts/stale-read-receipt.json +18 -0
- package/examples/context-attention-receipts/README.md +41 -0
- package/examples/context-attention-receipts/attention-receipt-fail.json +49 -0
- package/examples/context-attention-receipts/attention-receipt-pass.json +53 -0
- package/examples/context-attention-receipts/check-attention-receipt.mjs +97 -0
- package/examples/context-sufficiency-trace/README.md +22 -0
- package/examples/context-sufficiency-trace/check-context-sufficiency.mjs +40 -0
- package/examples/context-sufficiency-trace/context-trace-pass.json +28 -0
- package/examples/context-sufficiency-trace/context-trace.json +47 -0
- package/examples/context-sufficiency-trace/ground-truth.json +13 -0
- package/examples/provider-degradation-canaries/README.md +79 -0
- package/examples/provider-degradation-canaries/check-degradation-receipt.mjs +64 -0
- package/examples/provider-degradation-canaries/healthy-decision.json +27 -0
- package/examples/provider-degradation-canaries/unsafe-write-decision.json +26 -0
- package/examples/semantic-anchor-receipts/README.md +49 -0
- package/examples/semantic-anchor-receipts/check-semantic-anchors.mjs +153 -0
- package/examples/semantic-anchor-receipts/cleaned-paste.md +17 -0
- package/examples/semantic-anchor-receipts/original-paste.md +19 -0
- package/examples/semantic-anchor-receipts/sample-receipt.json +62 -0
- package/examples/session-preflight-receipts/README.md +25 -0
- package/examples/session-preflight-receipts/session-preflight-receipt.json +39 -0
- package/examples/session-preflight-receipts/session-preflight.mdc +18 -0
- package/examples/task-scoped-mcp-config/README.md +60 -0
- package/examples/task-scoped-mcp-config/mcp-catalog.json +46 -0
- package/examples/task-scoped-mcp-config/select-mcp-config.mjs +64 -0
- package/examples/task-scoped-mcp-config/tasks/browser-debug.json +7 -0
- package/package.json +5 -2
- package/skills/context-receipts/README.md +13 -2
- package/skills/context-receipts/SKILL.md +65 -0
- package/src/commands/demo.js +81 -1
- package/src/utils/version.js +1 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
|
|
4
|
+
const args = process.argv.slice(2);
|
|
5
|
+
const receiptPath = args[args.indexOf('--receipt') + 1];
|
|
6
|
+
if (!receiptPath || args.indexOf('--receipt') === -1) {
|
|
7
|
+
console.error('Usage: node check-degradation-receipt.mjs --receipt <path>');
|
|
8
|
+
process.exit(2);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const receipt = JSON.parse(fs.readFileSync(receiptPath, 'utf8'));
|
|
12
|
+
const errors = [];
|
|
13
|
+
const gates = new Set(['continue', 'read_only', 'fallback_model', 'pause_writes', 'stop']);
|
|
14
|
+
const confidences = new Set(['healthy', 'provider_degraded', 'app_bug', 'network', 'unknown']);
|
|
15
|
+
|
|
16
|
+
function requireString(field) {
|
|
17
|
+
if (!receipt[field] || typeof receipt[field] !== 'string') errors.push(`${field} must be a non-empty string`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (receipt.schema !== 'pluribus.provider_degradation_decision.v1') {
|
|
21
|
+
errors.push('schema must be pluribus.provider_degradation_decision.v1');
|
|
22
|
+
}
|
|
23
|
+
for (const field of ['run_id', 'provider', 'model', 'region', 'prompt_template_hash', 'canary_suite_version']) {
|
|
24
|
+
requireString(field);
|
|
25
|
+
}
|
|
26
|
+
if (!String(receipt.prompt_template_hash || '').startsWith('sha256:')) {
|
|
27
|
+
errors.push('prompt_template_hash must be a sha256: digest');
|
|
28
|
+
}
|
|
29
|
+
if (!gates.has(receipt.write_gate)) errors.push(`write_gate must be one of ${[...gates].join(', ')}`);
|
|
30
|
+
if (!confidences.has(receipt.confidence)) errors.push(`confidence must be one of ${[...confidences].join(', ')}`);
|
|
31
|
+
|
|
32
|
+
const t = receipt.transport || {};
|
|
33
|
+
for (const [field, limit] of Object.entries({ window_minutes: 1, ttft_p95_ms: 0, total_latency_p95_ms: 0, timeout_rate: 0, error_rate: 0, retry_count: 0 })) {
|
|
34
|
+
if (typeof t[field] !== 'number' || t[field] < limit) errors.push(`transport.${field} must be a number >= ${limit}`);
|
|
35
|
+
}
|
|
36
|
+
if (t.timeout_rate > 1 || t.error_rate > 1) errors.push('transport timeout/error rates must be <= 1');
|
|
37
|
+
|
|
38
|
+
if (!Array.isArray(receipt.capability_canaries) || receipt.capability_canaries.length < 3) {
|
|
39
|
+
errors.push('capability_canaries must include at least three app-critical canaries');
|
|
40
|
+
}
|
|
41
|
+
const canaries = receipt.capability_canaries || [];
|
|
42
|
+
const required = ['json_schema', 'tool_choice', 'patch_format'];
|
|
43
|
+
for (const name of required) {
|
|
44
|
+
if (!canaries.some((c) => c.name === name)) errors.push(`missing required canary: ${name}`);
|
|
45
|
+
}
|
|
46
|
+
const failingWriteBlockers = canaries.filter((c) => c.status === 'fail' && c.severity === 'write_blocking');
|
|
47
|
+
const degradedTransport = t.timeout_rate >= 0.05 || t.error_rate >= 0.05 || t.ttft_p95_ms >= 5000 || t.total_latency_p95_ms >= 30000;
|
|
48
|
+
if (degradedTransport && receipt.confidence === 'healthy') {
|
|
49
|
+
errors.push('confidence cannot be healthy when transport degradation thresholds are exceeded');
|
|
50
|
+
}
|
|
51
|
+
if (failingWriteBlockers.length > 0 && ['continue'].includes(receipt.write_gate)) {
|
|
52
|
+
errors.push(`write_gate cannot be continue when write-blocking canaries fail: ${failingWriteBlockers.map((c) => c.name).join(', ')}`);
|
|
53
|
+
}
|
|
54
|
+
if (receipt.confidence === 'provider_degraded' && receipt.write_gate === 'continue' && !receipt.fallback?.chosen) {
|
|
55
|
+
errors.push('provider_degraded decisions must choose fallback or block writes instead of continue');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (errors.length) {
|
|
59
|
+
console.error(`Degradation receipt failed (${receiptPath}):`);
|
|
60
|
+
for (const error of errors) console.error(`- ${error}`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log(`Degradation receipt passed: ${receiptPath}`);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "pluribus.provider_degradation_decision.v1",
|
|
3
|
+
"run_id": "agent-run-2026-06-15T20:02Z",
|
|
4
|
+
"provider": "anthropic",
|
|
5
|
+
"model": "claude-sonnet-4",
|
|
6
|
+
"region": "us-east-1",
|
|
7
|
+
"prompt_template_hash": "sha256:7a6c7f8b4fb1f3a9d4d9325e5c2a9dbb6b4cbf2e77b49e1f69b1a8d93d1f5c22",
|
|
8
|
+
"canary_suite_version": "coding-agent-smoke-2026-06-15",
|
|
9
|
+
"transport": {
|
|
10
|
+
"window_minutes": 10,
|
|
11
|
+
"ttft_p95_ms": 1400,
|
|
12
|
+
"total_latency_p95_ms": 9200,
|
|
13
|
+
"timeout_rate": 0.01,
|
|
14
|
+
"error_rate": 0,
|
|
15
|
+
"retry_count": 1,
|
|
16
|
+
"status_incident_url": null
|
|
17
|
+
},
|
|
18
|
+
"capability_canaries": [
|
|
19
|
+
{ "name": "json_schema", "status": "pass", "severity": "write_blocking" },
|
|
20
|
+
{ "name": "tool_choice", "status": "pass", "severity": "write_blocking" },
|
|
21
|
+
{ "name": "patch_format", "status": "pass", "severity": "write_blocking" },
|
|
22
|
+
{ "name": "citation_grounding", "status": "pass", "severity": "review_blocking" }
|
|
23
|
+
],
|
|
24
|
+
"fallback": { "chosen": false, "reason": null },
|
|
25
|
+
"confidence": "healthy",
|
|
26
|
+
"write_gate": "continue"
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "pluribus.provider_degradation_decision.v1",
|
|
3
|
+
"run_id": "agent-run-2026-06-15T20:11Z",
|
|
4
|
+
"provider": "anthropic",
|
|
5
|
+
"model": "claude-sonnet-4",
|
|
6
|
+
"region": "us-east-1",
|
|
7
|
+
"prompt_template_hash": "sha256:7a6c7f8b4fb1f3a9d4d9325e5c2a9dbb6b4cbf2e77b49e1f69b1a8d93d1f5c22",
|
|
8
|
+
"canary_suite_version": "coding-agent-smoke-2026-06-15",
|
|
9
|
+
"transport": {
|
|
10
|
+
"window_minutes": 10,
|
|
11
|
+
"ttft_p95_ms": 6200,
|
|
12
|
+
"total_latency_p95_ms": 41000,
|
|
13
|
+
"timeout_rate": 0.18,
|
|
14
|
+
"error_rate": 0.08,
|
|
15
|
+
"retry_count": 12,
|
|
16
|
+
"status_incident_url": null
|
|
17
|
+
},
|
|
18
|
+
"capability_canaries": [
|
|
19
|
+
{ "name": "json_schema", "status": "pass", "severity": "write_blocking" },
|
|
20
|
+
{ "name": "tool_choice", "status": "fail", "severity": "write_blocking", "evidence": "selected shell write tool for read-only prompt" },
|
|
21
|
+
{ "name": "patch_format", "status": "fail", "severity": "write_blocking", "evidence": "diff missing target file header" }
|
|
22
|
+
],
|
|
23
|
+
"fallback": { "chosen": false, "reason": null },
|
|
24
|
+
"confidence": "provider_degraded",
|
|
25
|
+
"write_gate": "continue"
|
|
26
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Semantic anchor preservation receipt
|
|
2
|
+
|
|
3
|
+
A tiny checker for Claude Code / Agent Skill workflows that claim big token savings by cleaning pasted context before it enters a session.
|
|
4
|
+
|
|
5
|
+
Token reduction is useful only if the cleaned paste keeps the anchors that make the task safe to execute: headings, code fences, API signatures, version/migration notes, and must-keep policy/security lines. This example emits a privacy-safe receipt for that claim without logging raw prompts or transcripts.
|
|
6
|
+
|
|
7
|
+
## Run it
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd examples/semantic-anchor-receipts
|
|
11
|
+
node check-semantic-anchors.mjs \
|
|
12
|
+
--original original-paste.md \
|
|
13
|
+
--cleaned cleaned-paste.md \
|
|
14
|
+
--out /tmp/semantic-anchor.receipt.json
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The bundled sample should pass and report a token reduction while preserving all detected anchors.
|
|
18
|
+
|
|
19
|
+
## Receipt shape
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"schema": "pluribus.semantic_anchor_preservation_receipt.v1",
|
|
24
|
+
"source_type": "paste-cleaning-skill-or-cli-output",
|
|
25
|
+
"approximate_tokens_before": 224,
|
|
26
|
+
"approximate_tokens_after": 110,
|
|
27
|
+
"approximate_reduction_percent": 50.9,
|
|
28
|
+
"anchors_total": 9,
|
|
29
|
+
"anchors_missing": 0,
|
|
30
|
+
"semantic_loss_check_passed": true,
|
|
31
|
+
"token_savings_claim_allowed": true
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The exact token counts are approximate. The important part is the gate:
|
|
36
|
+
|
|
37
|
+
- `semantic_loss_check_passed=true` means the cleaned paste preserved the detected anchors.
|
|
38
|
+
- `token_savings_claim_allowed=true` means the output both shrank and kept those anchors.
|
|
39
|
+
- If any anchor is missing, the checker exits non-zero and the receipt records the missing anchor types/text snippets.
|
|
40
|
+
|
|
41
|
+
## Why this exists
|
|
42
|
+
|
|
43
|
+
The market signal has moved beyond MCP tool bloat. Claude Code users are also using Skills and paste-cleaning CLIs that claim 50–70% token savings. Pluribus should not be another optimizer; it should make the optimizer's claim falsifiable:
|
|
44
|
+
|
|
45
|
+
- What was removed?
|
|
46
|
+
- Which must-keep anchors survived?
|
|
47
|
+
- Did a `SKILL.md` or CLI helper reduce tokens without deleting version, API, or security context?
|
|
48
|
+
|
|
49
|
+
Use this receipt before a cleaned paste becomes session context. Pair it with tool/skill adoption receipts later if you need to prove the agent actually used a loaded Skill or MCP tool.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
const args = { out: null };
|
|
7
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
8
|
+
const key = argv[i];
|
|
9
|
+
const value = argv[i + 1];
|
|
10
|
+
if (key === '--original') { args.original = value; i += 1; continue; }
|
|
11
|
+
if (key === '--cleaned') { args.cleaned = value; i += 1; continue; }
|
|
12
|
+
if (key === '--out') { args.out = value; i += 1; continue; }
|
|
13
|
+
if (key === '--help' || key === '-h') { args.help = true; continue; }
|
|
14
|
+
throw new Error(`Unknown argument: ${key}`);
|
|
15
|
+
}
|
|
16
|
+
return args;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function usage() {
|
|
20
|
+
return `Usage: node check-semantic-anchors.mjs --original original-paste.md --cleaned cleaned-paste.md [--out receipt.json]\n`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function normalize(value) {
|
|
24
|
+
return value
|
|
25
|
+
.replace(/`+/g, '')
|
|
26
|
+
.replace(/\s+/g, ' ')
|
|
27
|
+
.trim()
|
|
28
|
+
.toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function approxTokens(value) {
|
|
32
|
+
const chunks = value.trim().split(/\s+/).filter(Boolean).length;
|
|
33
|
+
return Math.max(1, Math.ceil(chunks * 1.33));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function extractAnchors(markdown) {
|
|
37
|
+
const anchors = [];
|
|
38
|
+
const lines = markdown.split(/\r?\n/);
|
|
39
|
+
let inFence = false;
|
|
40
|
+
let fenceLang = '';
|
|
41
|
+
let fenceLines = [];
|
|
42
|
+
|
|
43
|
+
function push(type, text, extra = {}) {
|
|
44
|
+
const canonical = normalize(text);
|
|
45
|
+
if (!canonical) return;
|
|
46
|
+
anchors.push({ type, text: text.trim(), canonical, ...extra });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (const line of lines) {
|
|
50
|
+
const fence = line.match(/^```\s*([\w-]*)/);
|
|
51
|
+
if (fence) {
|
|
52
|
+
if (!inFence) {
|
|
53
|
+
inFence = true;
|
|
54
|
+
fenceLang = fence[1] || 'plain';
|
|
55
|
+
fenceLines = [];
|
|
56
|
+
} else {
|
|
57
|
+
const body = fenceLines.join('\n').trim();
|
|
58
|
+
if (body) push('code_fence', body, { language: fenceLang });
|
|
59
|
+
inFence = false;
|
|
60
|
+
fenceLang = '';
|
|
61
|
+
fenceLines = [];
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (inFence) {
|
|
67
|
+
fenceLines.push(line);
|
|
68
|
+
const sig = line.match(/\b(export\s+)?(async\s+)?(function|class|interface|type|def)\s+[A-Za-z0-9_]+[^;{]*/);
|
|
69
|
+
if (sig) push('api_signature', sig[0]);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (/^#{1,4}\s+\S/.test(line)) push('heading', line.replace(/^#{1,4}\s+/, ''));
|
|
74
|
+
if (/\b(v?\d+\.\d+(?:\.\d+)?)\b/.test(line) && /\b(version|v\d|deprecated|removed|migration|upgrade|breaking|changed)\b/i.test(line)) {
|
|
75
|
+
push('version_or_migration_note', line);
|
|
76
|
+
}
|
|
77
|
+
if (/\b(never|must|do not|required|preserve|security|constraint)\b/i.test(line)) {
|
|
78
|
+
push('must_keep_policy', line.replace(/^[-*]\s+/, ''));
|
|
79
|
+
}
|
|
80
|
+
const sig = line.match(/\b(export\s+)?(async\s+)?(function|class|interface|type|def)\s+[A-Za-z0-9_]+[^;{]*/);
|
|
81
|
+
if (sig) push('api_signature', sig[0]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const seen = new Set();
|
|
85
|
+
return anchors.filter((anchor) => {
|
|
86
|
+
const key = `${anchor.type}:${anchor.canonical}`;
|
|
87
|
+
if (seen.has(key)) return false;
|
|
88
|
+
seen.add(key);
|
|
89
|
+
return true;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function main() {
|
|
94
|
+
const args = parseArgs(process.argv.slice(2));
|
|
95
|
+
if (args.help) { process.stdout.write(usage()); return; }
|
|
96
|
+
if (!args.original || !args.cleaned) throw new Error(usage().trim());
|
|
97
|
+
|
|
98
|
+
const originalPath = path.resolve(args.original);
|
|
99
|
+
const cleanedPath = path.resolve(args.cleaned);
|
|
100
|
+
const original = fs.readFileSync(originalPath, 'utf8');
|
|
101
|
+
const cleaned = fs.readFileSync(cleanedPath, 'utf8');
|
|
102
|
+
const cleanedCanonical = normalize(cleaned);
|
|
103
|
+
const anchors = extractAnchors(original);
|
|
104
|
+
const preserved = [];
|
|
105
|
+
const missing = [];
|
|
106
|
+
|
|
107
|
+
for (const anchor of anchors) {
|
|
108
|
+
const keep = cleanedCanonical.includes(anchor.canonical);
|
|
109
|
+
const compactAnchor = { type: anchor.type, text: anchor.text };
|
|
110
|
+
if (anchor.language) compactAnchor.language = anchor.language;
|
|
111
|
+
(keep ? preserved : missing).push(compactAnchor);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const before = approxTokens(original);
|
|
115
|
+
const after = approxTokens(cleaned);
|
|
116
|
+
const reduction = Number((((before - after) / before) * 100).toFixed(1));
|
|
117
|
+
const receipt = {
|
|
118
|
+
schema: 'pluribus.semantic_anchor_preservation_receipt.v1',
|
|
119
|
+
source_type: 'paste-cleaning-skill-or-cli-output',
|
|
120
|
+
original_ref: path.basename(originalPath),
|
|
121
|
+
cleaned_ref: path.basename(cleanedPath),
|
|
122
|
+
approximate_tokens_before: before,
|
|
123
|
+
approximate_tokens_after: after,
|
|
124
|
+
approximate_reduction_percent: reduction,
|
|
125
|
+
raw_source_logged: false,
|
|
126
|
+
anchor_detection_policy: [
|
|
127
|
+
'headings',
|
|
128
|
+
'code_fences',
|
|
129
|
+
'api_signatures',
|
|
130
|
+
'version_or_migration_notes',
|
|
131
|
+
'must_keep_policy_lines'
|
|
132
|
+
],
|
|
133
|
+
anchors_total: anchors.length,
|
|
134
|
+
anchors_preserved: preserved.length,
|
|
135
|
+
anchors_missing: missing.length,
|
|
136
|
+
preserved_anchors: preserved,
|
|
137
|
+
missing_anchors: missing,
|
|
138
|
+
semantic_loss_check_passed: missing.length === 0,
|
|
139
|
+
token_savings_claim_allowed: missing.length === 0 && after < before
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const serialized = `${JSON.stringify(receipt, null, 2)}\n`;
|
|
143
|
+
if (args.out) fs.writeFileSync(path.resolve(args.out), serialized);
|
|
144
|
+
process.stdout.write(serialized);
|
|
145
|
+
if (!receipt.semantic_loss_check_passed) process.exitCode = 1;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
main();
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error(error.message);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Upload API v2 migration notes
|
|
2
|
+
|
|
3
|
+
The `uploadFile` helper changed in v2.4.0. Keep this version note because older snippets still use v1.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
export async function uploadFile(input: UploadInput): Promise<UploadResult> {
|
|
7
|
+
return client.files.upload(input)
|
|
8
|
+
}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Required behavior
|
|
12
|
+
|
|
13
|
+
- Preserve the retry policy: max 3 attempts with exponential backoff.
|
|
14
|
+
- Do not strip the security constraint: never log raw file contents.
|
|
15
|
+
- Deprecated: `uploadLegacy(path)` is removed after v2.5.0.
|
|
16
|
+
|
|
17
|
+
Most verbose examples were removed, but the API signature, version notes, and security constraint survive.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Upload API v2 migration notes
|
|
2
|
+
|
|
3
|
+
The `uploadFile` helper changed in v2.4.0. Keep this version note because older snippets still use v1.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
export async function uploadFile(input: UploadInput): Promise<UploadResult> {
|
|
7
|
+
return client.files.upload(input)
|
|
8
|
+
}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Required behavior
|
|
12
|
+
|
|
13
|
+
- Preserve the retry policy: max 3 attempts with exponential backoff.
|
|
14
|
+
- Do not strip the security constraint: never log raw file contents.
|
|
15
|
+
- Deprecated: `uploadLegacy(path)` is removed after v2.5.0.
|
|
16
|
+
|
|
17
|
+
Most examples below are verbose and can be compressed before pasting into Claude Code once the important anchors are checked.
|
|
18
|
+
|
|
19
|
+
Long example narrative: in staging we saw several users retry uploads manually after a network timeout, then paste screenshots and unrelated logs into the issue. The cleaned context does not need every anecdote, every repeated stack frame, or every copy of the same explanatory paragraph. It only needs enough surrounding language for the agent to understand the migration target after the anchors above are preserved. Remove repeated examples, duplicated support notes, and verbose operational chatter before the paste enters the session.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "pluribus.semantic_anchor_preservation_receipt.v1",
|
|
3
|
+
"source_type": "paste-cleaning-skill-or-cli-output",
|
|
4
|
+
"original_ref": "original-paste.md",
|
|
5
|
+
"cleaned_ref": "cleaned-paste.md",
|
|
6
|
+
"approximate_tokens_before": 224,
|
|
7
|
+
"approximate_tokens_after": 110,
|
|
8
|
+
"approximate_reduction_percent": 50.9,
|
|
9
|
+
"raw_source_logged": false,
|
|
10
|
+
"anchor_detection_policy": [
|
|
11
|
+
"headings",
|
|
12
|
+
"code_fences",
|
|
13
|
+
"api_signatures",
|
|
14
|
+
"version_or_migration_notes",
|
|
15
|
+
"must_keep_policy_lines"
|
|
16
|
+
],
|
|
17
|
+
"anchors_total": 9,
|
|
18
|
+
"anchors_preserved": 9,
|
|
19
|
+
"anchors_missing": 0,
|
|
20
|
+
"preserved_anchors": [
|
|
21
|
+
{
|
|
22
|
+
"type": "heading",
|
|
23
|
+
"text": "Upload API v2 migration notes"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"type": "version_or_migration_note",
|
|
27
|
+
"text": "The `uploadFile` helper changed in v2.4.0. Keep this version note because older snippets still use v1."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"type": "api_signature",
|
|
31
|
+
"text": "export async function uploadFile(input: UploadInput): Promise<UploadResult>"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "code_fence",
|
|
35
|
+
"text": "export async function uploadFile(input: UploadInput): Promise<UploadResult> {\n return client.files.upload(input)\n}",
|
|
36
|
+
"language": "ts"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"type": "heading",
|
|
40
|
+
"text": "Required behavior"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"type": "must_keep_policy",
|
|
44
|
+
"text": "## Required behavior"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "must_keep_policy",
|
|
48
|
+
"text": "Preserve the retry policy: max 3 attempts with exponential backoff."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "must_keep_policy",
|
|
52
|
+
"text": "Do not strip the security constraint: never log raw file contents."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"type": "version_or_migration_note",
|
|
56
|
+
"text": "- Deprecated: `uploadLegacy(path)` is removed after v2.5.0."
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"missing_anchors": [],
|
|
60
|
+
"semantic_loss_check_passed": true,
|
|
61
|
+
"token_savings_claim_allowed": true
|
|
62
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Session preflight receipt example
|
|
2
|
+
|
|
3
|
+
This example is for Cursor/Claude Code/MCP workflows where a project wants a required first step before agent work, such as `session_guard.session_init` or reading `MEMORY.md`.
|
|
4
|
+
|
|
5
|
+
It turns a behavioral instruction into a reviewable artifact:
|
|
6
|
+
|
|
7
|
+
1. The rule says the agent must initialize context first.
|
|
8
|
+
2. The receipt records whether the required context was loaded.
|
|
9
|
+
3. The decision says whether the run may proceed, must stay read-only, or should stop.
|
|
10
|
+
|
|
11
|
+
Copy the sample rule into `.cursor/rules/session-preflight.mdc` and adapt the JSON fields to your local guard/MCP server.
|
|
12
|
+
|
|
13
|
+
## Try it
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
node -e "const fs=require('fs'); const r=JSON.parse(fs.readFileSync('examples/session-preflight-receipts/session-preflight-receipt.json','utf8')); if (!r.decision.allowed_to_start_work) process.exit(1); console.log(r.schema, r.decision.mode)"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Expected output:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
pluribus.session_preflight_receipt.v1 read_then_patch
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This does not enforce Cursor's tool calls by itself. It gives teams a concrete evidence object to ask for when evaluating required-first-tool or pre-tool-hook workflows.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "pluribus.session_preflight_receipt.v1",
|
|
3
|
+
"session_id": "local-2026-06-17T11:00Z",
|
|
4
|
+
"client": "cursor",
|
|
5
|
+
"required_first_step": {
|
|
6
|
+
"kind": "mcp_tool",
|
|
7
|
+
"name": "session_guard.session_init",
|
|
8
|
+
"enforcement": "behavioral_rule_only"
|
|
9
|
+
},
|
|
10
|
+
"required_context": [
|
|
11
|
+
{
|
|
12
|
+
"id": "project-memory",
|
|
13
|
+
"path": "MEMORY.md",
|
|
14
|
+
"status": "loaded",
|
|
15
|
+
"fingerprint": "sha256:replace-with-non-secret-digest"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "project-rules",
|
|
19
|
+
"path": ".cursor/rules/session-preflight.mdc",
|
|
20
|
+
"status": "loaded",
|
|
21
|
+
"fingerprint": "sha256:replace-with-non-secret-digest"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"tool_surface": {
|
|
25
|
+
"mcp_servers_seen": ["session-guard", "playwright"],
|
|
26
|
+
"side_effecting_tools_blocked_until_preflight": ["Shell", "Write"],
|
|
27
|
+
"read_only_tools_allowed_before_preflight": ["Read"]
|
|
28
|
+
},
|
|
29
|
+
"decision": {
|
|
30
|
+
"allowed_to_start_work": true,
|
|
31
|
+
"mode": "read_then_patch",
|
|
32
|
+
"reason": "required project memory and rules were checked before side-effecting tool use"
|
|
33
|
+
},
|
|
34
|
+
"privacy": {
|
|
35
|
+
"raw_context_logged": false,
|
|
36
|
+
"secrets_logged": false,
|
|
37
|
+
"fingerprints_only": true
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Require a visible session preflight before side-effecting agent work.
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Before using Shell, Write, Apply Patch, or external MCP tools, produce a session preflight receipt.
|
|
7
|
+
|
|
8
|
+
The receipt must state:
|
|
9
|
+
|
|
10
|
+
- required first step: `session_guard.session_init` or the local equivalent
|
|
11
|
+
- required context files checked, such as `MEMORY.md`, `AGENTS.md`, `.cursor/rules/*.mdc`, or `CLAUDE.md`
|
|
12
|
+
- whether only read-only tools are allowed before preflight
|
|
13
|
+
- proceed mode: `read_only`, `read_then_patch`, `stop`, or `ask_human`
|
|
14
|
+
- reason for the mode
|
|
15
|
+
|
|
16
|
+
Do not paste raw memory or secrets into the receipt. Use status and non-secret fingerprints instead.
|
|
17
|
+
|
|
18
|
+
If the preflight is missing or required context is unavailable, stay in `read_only` mode and ask for the missing context before edits.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Task-scoped MCP config receipt
|
|
2
|
+
|
|
3
|
+
A tiny demo for the Claude Code / MCP context-bloat complaint: MCP tools can consume context before they are used. One practical workaround is to keep a catalog of MCP server configs and start the agent with a task-specific `--mcp-config` instead of loading every server every time.
|
|
4
|
+
|
|
5
|
+
This example makes that workaround auditable. It produces:
|
|
6
|
+
|
|
7
|
+
1. a minimal Claude Code-compatible MCP config for one task; and
|
|
8
|
+
2. a privacy-safe receipt showing which servers were selected, which were withheld, and why.
|
|
9
|
+
|
|
10
|
+
It deliberately does **not** claim adoption. A selected MCP server is only agent-visible; a later tool-adoption receipt would still be needed to prove the agent called it.
|
|
11
|
+
|
|
12
|
+
## Run it
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
cd examples/task-scoped-mcp-config
|
|
16
|
+
node select-mcp-config.mjs \
|
|
17
|
+
--task tasks/browser-debug.json \
|
|
18
|
+
--out /tmp/browser-debug.mcp.json \
|
|
19
|
+
--receipt /tmp/browser-debug.receipt.json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Use the generated config with Claude Code or a compatible client:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
claude --mcp-config /tmp/browser-debug.mcp.json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The demo catalog includes five plausible MCP servers. The `browser-debug` task selects only `playwright` and `context7`, withholding memory, observability, and repo-operation servers for the first pass.
|
|
29
|
+
|
|
30
|
+
## Receipt shape
|
|
31
|
+
|
|
32
|
+
The receipt is intentionally low-cardinality:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"schema": "pluribus.task_scoped_mcp_config_receipt.v1",
|
|
37
|
+
"task_id": "browser-debug",
|
|
38
|
+
"selected_server_ids": ["playwright", "context7"],
|
|
39
|
+
"withheld_server_ids": ["sentry", "openmemory", "github"],
|
|
40
|
+
"selected_estimated_schema_tokens": 20000,
|
|
41
|
+
"withheld_estimated_schema_tokens": 24000,
|
|
42
|
+
"raw_tool_schemas_logged": false,
|
|
43
|
+
"adoption_claim_allowed": false
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Use it to review the initial context surface:
|
|
48
|
+
|
|
49
|
+
- Did this task need every MCP server, or only a small subset?
|
|
50
|
+
- Which server descriptions were kept out of the first context window?
|
|
51
|
+
- Are we accidentally claiming “the agent used the tool” when we only proved “the tool was selected into the config”?
|
|
52
|
+
|
|
53
|
+
## Why this exists
|
|
54
|
+
|
|
55
|
+
The market signal is not “MCP is bad.” It is that large tool catalogs need two separate proofs:
|
|
56
|
+
|
|
57
|
+
- **Surface proof:** which tools/servers were made visible for this task?
|
|
58
|
+
- **Adoption proof:** which visible tools were actually called, cited, or used before claims/edits?
|
|
59
|
+
|
|
60
|
+
This demo covers only the first proof. Pair it with a tool-adoption receipt when you need the second.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "pluribus.mcp_catalog.v1",
|
|
3
|
+
"catalogId": "demo-claude-code-mcp-catalog",
|
|
4
|
+
"servers": [
|
|
5
|
+
{
|
|
6
|
+
"id": "playwright",
|
|
7
|
+
"command": "npx",
|
|
8
|
+
"args": ["@playwright/mcp@latest"],
|
|
9
|
+
"category": "browser_automation",
|
|
10
|
+
"estimatedSchemaTokens": 11800,
|
|
11
|
+
"taskTags": ["browser", "web-debug", "e2e"]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "context7",
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": ["@upstash/context7-mcp@latest"],
|
|
17
|
+
"category": "docs_lookup",
|
|
18
|
+
"estimatedSchemaTokens": 8200,
|
|
19
|
+
"taskTags": ["docs", "api-reference"]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "sentry",
|
|
23
|
+
"command": "npx",
|
|
24
|
+
"args": ["@sentry/mcp-server@latest"],
|
|
25
|
+
"category": "observability",
|
|
26
|
+
"estimatedSchemaTokens": 9700,
|
|
27
|
+
"taskTags": ["errors", "production-debug"]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "openmemory",
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["openmemory-mcp@latest"],
|
|
33
|
+
"category": "memory",
|
|
34
|
+
"estimatedSchemaTokens": 6900,
|
|
35
|
+
"taskTags": ["memory", "recall"]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "github",
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["@modelcontextprotocol/server-github@latest"],
|
|
41
|
+
"category": "repo_ops",
|
|
42
|
+
"estimatedSchemaTokens": 7400,
|
|
43
|
+
"taskTags": ["issues", "pull-requests", "repo"]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|