auxilo-mcp 0.9.0 → 0.9.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.
- package/README.md +132 -135
- package/bin/auxilo-cli.js +230 -68
- package/lib/installer.js +5 -1
- package/lib/review.js +170 -3
- package/mcp-server.js +330 -138
- package/package.json +12 -6
- package/scripts/extract-local.js +119 -0
- package/scripts/runner.js +54 -30
- package/prompts/auxilo-learning-claude-code.md +0 -250
- package/prompts/auxilo-learning-generic.md +0 -327
- package/prompts/auxilo-learning-schema.json +0 -98
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "auxilo-mcp",
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.9.2",
|
|
4
|
+
"mcpName": "io.github.silent-architects/auxilo",
|
|
5
|
+
"description": "MCP server for Auxilo. Your agent stops solving the same problem twice: auto-extracted learnings, free self-unlocks, and earnings when other agents unlock yours.",
|
|
5
6
|
"main": "mcp-server.js",
|
|
6
7
|
"bin": {
|
|
7
8
|
"auxilo-mcp": "mcp-server.js",
|
|
@@ -15,13 +16,11 @@
|
|
|
15
16
|
"lib/sensitivity-filter.js",
|
|
16
17
|
"scripts/runner.js",
|
|
17
18
|
"scripts/capture-core.js",
|
|
19
|
+
"scripts/extract-local.js",
|
|
18
20
|
"scripts/sources/",
|
|
19
21
|
"scripts/hooks/auxilo-extract.sh",
|
|
20
22
|
"README.md",
|
|
21
|
-
"LICENSE"
|
|
22
|
-
"prompts/auxilo-learning-claude-code.md",
|
|
23
|
-
"prompts/auxilo-learning-generic.md",
|
|
24
|
-
"prompts/auxilo-learning-schema.json"
|
|
23
|
+
"LICENSE"
|
|
25
24
|
],
|
|
26
25
|
"scripts": {
|
|
27
26
|
"start": "node mcp-server.js",
|
|
@@ -29,9 +28,16 @@
|
|
|
29
28
|
},
|
|
30
29
|
"keywords": [
|
|
31
30
|
"mcp",
|
|
31
|
+
"mcp-server",
|
|
32
32
|
"model-context-protocol",
|
|
33
|
+
"claude",
|
|
34
|
+
"claude-code",
|
|
35
|
+
"cursor",
|
|
36
|
+
"windsurf",
|
|
33
37
|
"ai-agents",
|
|
38
|
+
"agent-learning",
|
|
34
39
|
"agent-discovery",
|
|
40
|
+
"knowledge-sharing",
|
|
35
41
|
"knowledge-marketplace",
|
|
36
42
|
"x402",
|
|
37
43
|
"auxilo"
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*
|
|
3
|
+
* scripts/extract-local.js — CLIENT-SIDE learning extraction using the user's OWN model.
|
|
4
|
+
*
|
|
5
|
+
* Auxilo does not pay to extract. At session end, the agent that just did the work
|
|
6
|
+
* (itself an LLM) extracts reusable learnings AND self-screens them for sensitivity,
|
|
7
|
+
* using the local client's model (`claude -p` for Claude Code). Finished learnings are
|
|
8
|
+
* then submitted to POST /learn by the runner. Zero cost to Auxilo.
|
|
9
|
+
*
|
|
10
|
+
* RECURSION SAFETY: `claude -p` starts a headless Claude Code turn, which will itself
|
|
11
|
+
* fire the SessionEnd hook. We set AUXILO_EXTRACTING=1 on the child env so that child's
|
|
12
|
+
* runner no-ops immediately (runner.js checks it). runner.js also sets it in-process
|
|
13
|
+
* before we're called; we set it on the child explicitly as belt-and-suspenders.
|
|
14
|
+
*/
|
|
15
|
+
const { spawnSync } = require('child_process');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const os = require('os');
|
|
19
|
+
|
|
20
|
+
const CATEGORIES = ['data-processing', 'web-interaction', 'code-execution', 'communication', 'storage-state', 'content-generation', 'payment-financial', 'monitoring'];
|
|
21
|
+
|
|
22
|
+
const EXTRACTION_PROMPT = `You are extracting reusable OPERATIONAL LEARNINGS from an AI agent's session transcript, to publish to a PUBLIC knowledge marketplace read by other AI agents.
|
|
23
|
+
|
|
24
|
+
Extract 0 to 5 GENUINE learnings: non-obvious solutions, workarounds, API quirks, error root-causes, integration gotchas — the kind of thing that cost real debugging or combined multiple sources. SKIP trivial lookups, well-documented standard approaches, opinions, and conversation.
|
|
25
|
+
|
|
26
|
+
MANDATORY SENSITIVITY SELF-SCREEN (the marketplace is PUBLIC): NEVER include secrets, credentials, API keys, tokens, private keys, or seed phrases; personal data (real people's names, emails, phone numbers, wallet addresses); private filesystem paths, internal hostnames, or infrastructure identifiers; proprietary, confidential, or client-specific business content. Rewrite specifics into generic placeholders (/Users/USER/..., API_KEY, "a client") or omit them. If a learning cannot be generalized without leaking private material, DROP it entirely.
|
|
27
|
+
|
|
28
|
+
Output STRICT JSON ONLY — an array (possibly empty []) of objects with these keys:
|
|
29
|
+
"title": concise, >= 10 chars
|
|
30
|
+
"body": >= 50 chars — what was tried, what worked, what failed
|
|
31
|
+
"category": one of ${JSON.stringify(CATEGORIES)}
|
|
32
|
+
"tags": array of lowercase keyword strings
|
|
33
|
+
"task_context": one sentence describing the task
|
|
34
|
+
"outcome": one of "success","partial","failure","workaround"
|
|
35
|
+
No prose, no explanation, no markdown code fences — just the raw JSON array.
|
|
36
|
+
|
|
37
|
+
TRANSCRIPT:
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
/** Resolve the `claude` binary — hook/launchd env may have a minimal PATH. */
|
|
41
|
+
function resolveClaudeBin() {
|
|
42
|
+
const candidates = [
|
|
43
|
+
'claude',
|
|
44
|
+
path.join(os.homedir(), '.claude', 'local', 'claude'),
|
|
45
|
+
'/usr/local/bin/claude',
|
|
46
|
+
'/opt/homebrew/bin/claude',
|
|
47
|
+
path.join(os.homedir(), '.local', 'bin', 'claude'),
|
|
48
|
+
];
|
|
49
|
+
for (const c of candidates) {
|
|
50
|
+
try {
|
|
51
|
+
if (c === 'claude') return c; // let PATH resolve it; spawn will ENOENT if absent
|
|
52
|
+
if (fs.existsSync(c)) return c;
|
|
53
|
+
} catch (_) { /* ignore */ }
|
|
54
|
+
}
|
|
55
|
+
return 'claude';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Invoke the local Claude Code model headlessly (uses the USER's subscription auth).
|
|
60
|
+
* Prompt+transcript go via stdin. Returns { ok, out, reason } — never throws, so the
|
|
61
|
+
* SessionEnd hook degrades gracefully (the proactive auxilo_contribute path is the
|
|
62
|
+
* reliable primary; this deterministic hook is best-effort).
|
|
63
|
+
*/
|
|
64
|
+
function extractWithClaudeCode(transcript) {
|
|
65
|
+
const bin = resolveClaudeBin();
|
|
66
|
+
const input = EXTRACTION_PROMPT + String(transcript).slice(0, 200000);
|
|
67
|
+
// Do NOT pass ANTHROPIC_API_KEY through — we want the user's logged-in Claude
|
|
68
|
+
// subscription (OAuth), not an API key (which would bill someone). Delete it.
|
|
69
|
+
const childEnv = { ...process.env, AUXILO_EXTRACTING: '1' };
|
|
70
|
+
delete childEnv.ANTHROPIC_API_KEY;
|
|
71
|
+
const res = spawnSync(bin, ['-p'], { input, encoding: 'utf-8', env: childEnv, timeout: 120000, maxBuffer: 20 * 1024 * 1024 });
|
|
72
|
+
const out = String(res.stdout || '');
|
|
73
|
+
if (res.error) return { ok: false, out: '', reason: `spawn failed (${bin}): ${res.error.message}` };
|
|
74
|
+
// Claude prints auth failures ("API Error: 401 ... Please run /login") to stdout.
|
|
75
|
+
if (/Please run \/login|authentication_error|401/i.test(out) || /Please run \/login|authentication_error/i.test(String(res.stderr || ''))) {
|
|
76
|
+
return { ok: false, out, reason: 'local model not authenticated in this context (run `claude` and /login once); skipping deterministic extraction' };
|
|
77
|
+
}
|
|
78
|
+
if (res.status !== 0) return { ok: false, out, reason: `local model exited ${res.status}: ${(out || String(res.stderr || '')).slice(0, 160)}` };
|
|
79
|
+
return { ok: true, out, reason: null };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Defensively parse a JSON array of learnings out of model output. */
|
|
83
|
+
function parseLearnings(raw) {
|
|
84
|
+
let s = String(raw || '').trim();
|
|
85
|
+
const fence = s.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
86
|
+
if (fence) s = fence[1].trim();
|
|
87
|
+
const start = s.indexOf('[');
|
|
88
|
+
const end = s.lastIndexOf(']');
|
|
89
|
+
if (start === -1 || end === -1 || end < start) return [];
|
|
90
|
+
let arr;
|
|
91
|
+
try { arr = JSON.parse(s.slice(start, end + 1)); } catch (_) { return []; }
|
|
92
|
+
if (!Array.isArray(arr)) return [];
|
|
93
|
+
return arr
|
|
94
|
+
.filter(l => l && typeof l.title === 'string' && typeof l.body === 'string' && l.title.length >= 10 && l.body.length >= 50)
|
|
95
|
+
.map(l => ({
|
|
96
|
+
title: l.title,
|
|
97
|
+
body: l.body,
|
|
98
|
+
category: CATEGORIES.includes(l.category) ? l.category : 'code-execution',
|
|
99
|
+
tags: Array.isArray(l.tags) ? l.tags.slice(0, 8).map(String) : [],
|
|
100
|
+
task_context: typeof l.task_context === 'string' ? l.task_context : '',
|
|
101
|
+
outcome: ['success', 'partial', 'failure', 'workaround'].includes(l.outcome) ? l.outcome : 'success',
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Extract learnings locally. Returns { learnings: [...] } or { learnings: [], skipped }.
|
|
107
|
+
* Only claude-code has a local extractor today; other clients rely on the agent's
|
|
108
|
+
* proactive auxilo_contribute (MCP) call.
|
|
109
|
+
*/
|
|
110
|
+
async function extractLocally(transcript, sourceType) {
|
|
111
|
+
if (sourceType && sourceType !== 'claude-code') {
|
|
112
|
+
return { learnings: [], skipped: `local extraction not implemented for "${sourceType}" — agent contributes via auxilo_contribute` };
|
|
113
|
+
}
|
|
114
|
+
const { ok, out, reason } = extractWithClaudeCode(transcript);
|
|
115
|
+
if (!ok) return { learnings: [], skipped: reason };
|
|
116
|
+
return { learnings: parseLearnings(out) };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = { extractLocally, parseLearnings, resolveClaudeBin, EXTRACTION_PROMPT, CATEGORIES };
|
package/scripts/runner.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Transport layer for the autonomous extraction pipeline:
|
|
7
7
|
* 1. Check kill-switch sentinel + recursion guard (A5.2)
|
|
8
8
|
* 2. Enumerate active sources via TranscriptSource interface (A5.1)
|
|
9
|
-
* 3. For each new session: readSession() → client-side scrub → write queue file → POST /
|
|
9
|
+
* 3. For each new session: readSession() → client-side scrub → write queue file → local extraction → POST /learn
|
|
10
10
|
* 4. On success: update ledger, delete queue file. On failure: leave queue file.
|
|
11
11
|
*
|
|
12
12
|
* Usage:
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* node scripts/runner.js --force # ignore ledger high-water
|
|
24
24
|
*
|
|
25
25
|
* Environment:
|
|
26
|
-
* AUXILO_API_KEY — API key for authenticated /
|
|
26
|
+
* AUXILO_API_KEY — API key for authenticated /learn submissions (REQUIRED unless --dry-run)
|
|
27
27
|
* AUXILO_BASE_URL — Server URL (default: http://localhost:49152)
|
|
28
28
|
* AUXILO_EXTRACTING — Recursion guard (A5.2); set to "1" by this runner
|
|
29
29
|
*
|
|
@@ -186,7 +186,7 @@ function ledgerMark(ledger, sourceId, sessionId, sha, mtime) {
|
|
|
186
186
|
let queueCounter = Date.now();
|
|
187
187
|
|
|
188
188
|
/**
|
|
189
|
-
* Write a queue file BEFORE
|
|
189
|
+
* Write a queue file BEFORE local extraction and the /learn submissions.
|
|
190
190
|
* B6: Uses O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW with mode 0o600 to prevent
|
|
191
191
|
* symlink attacks on the pending-learnings directory.
|
|
192
192
|
*
|
|
@@ -233,30 +233,52 @@ function listPendingFiles() {
|
|
|
233
233
|
|
|
234
234
|
// ─── Upload ─────────────────────────────────────────────────────────────────
|
|
235
235
|
|
|
236
|
-
async function postExtract(transcript, sessionId, sourceType,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}),
|
|
253
|
-
});
|
|
236
|
+
async function postExtract(transcript, sessionId, sourceType, _scrubReport) {
|
|
237
|
+
// CLIENT-SIDE extraction (2026-07-02). Server /extract is deprecated (410) — Auxilo
|
|
238
|
+
// does not pay to extract. The local model (via `claude -p`) extracts + self-screens
|
|
239
|
+
// the already-client-scrubbed transcript, and we submit finished learnings to /learn.
|
|
240
|
+
const { extractLocally } = require('./extract-local.js');
|
|
241
|
+
let learnings;
|
|
242
|
+
let skipped;
|
|
243
|
+
try {
|
|
244
|
+
({ learnings, skipped } = await extractLocally(transcript, sourceType));
|
|
245
|
+
} catch (err) {
|
|
246
|
+
throw new Error(`Local extraction failed: ${err.message}`);
|
|
247
|
+
}
|
|
248
|
+
if (skipped) {
|
|
249
|
+
log(`[runner] ${skipped}`);
|
|
250
|
+
return { learnings_published: 0, learnings_rejected: 0, extraction_id: 'client-skip' };
|
|
251
|
+
}
|
|
254
252
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
253
|
+
let published = 0;
|
|
254
|
+
let rejected = 0;
|
|
255
|
+
for (const l of learnings) {
|
|
256
|
+
try {
|
|
257
|
+
const res = await fetch(`${BASE_URL}/learn`, {
|
|
258
|
+
method: 'POST',
|
|
259
|
+
headers: {
|
|
260
|
+
'Content-Type': 'application/json',
|
|
261
|
+
'X-API-Key': API_KEY,
|
|
262
|
+
'Idempotency-Key': crypto.randomUUID(),
|
|
263
|
+
},
|
|
264
|
+
body: JSON.stringify({
|
|
265
|
+
title: l.title,
|
|
266
|
+
body: l.body,
|
|
267
|
+
category: l.category,
|
|
268
|
+
tags: l.tags,
|
|
269
|
+
task_context: l.task_context,
|
|
270
|
+
outcome: l.outcome,
|
|
271
|
+
contributor_agent: `auxilo-hook/${sourceType}`,
|
|
272
|
+
}),
|
|
273
|
+
});
|
|
274
|
+
if (res.ok) published += 1;
|
|
275
|
+
else rejected += 1;
|
|
276
|
+
} catch (_) {
|
|
277
|
+
rejected += 1;
|
|
278
|
+
}
|
|
258
279
|
}
|
|
259
|
-
|
|
280
|
+
log(`[runner] client-side extraction: ${learnings.length} candidate(s), published=${published} rejected=${rejected}`);
|
|
281
|
+
return { learnings_published: published, learnings_rejected: rejected, extraction_id: `client-${sessionId}` };
|
|
260
282
|
}
|
|
261
283
|
|
|
262
284
|
// ─── Install Hooks (B15) ────────────────────────────────────────────────────
|
|
@@ -337,7 +359,8 @@ function installHooks() {
|
|
|
337
359
|
// ~/Documents would still be TCC-blocked) — and point the LaunchAgent plist
|
|
338
360
|
// at the installed copy. Re-run after changing any of these files.
|
|
339
361
|
|
|
340
|
-
|
|
362
|
+
// Renamed 2026-07-15: the original label carried a dead pre-Fly host prefix (legacy-label purge).
|
|
363
|
+
const SWEEPER_LABEL = 'io.auxilo.sweeper';
|
|
341
364
|
|
|
342
365
|
function installSweeper() {
|
|
343
366
|
const repoRoot = path.resolve(__dirname, '..');
|
|
@@ -419,7 +442,7 @@ function installSweeper() {
|
|
|
419
442
|
|
|
420
443
|
// ─── Install Daily Digest (P1-13 follow-up) ─────────────────────────────────
|
|
421
444
|
//
|
|
422
|
-
// Same TCC root cause as the sweeper: the original
|
|
445
|
+
// Same TCC root cause as the sweeper: the original digest
|
|
423
446
|
// plist ran node against jobs/daily-digest.js under ~/Documents, which launchd
|
|
424
447
|
// cannot read ("Unknown system error -11" in daily-digest.stderr.log). The
|
|
425
448
|
// digest is a purely local job — it summarizes ~/.auxilo/extract.log — so the
|
|
@@ -427,7 +450,8 @@ function installSweeper() {
|
|
|
427
450
|
// daily-digest.js is self-contained (fs/path/os only), so it is the only file
|
|
428
451
|
// to copy. Re-run after changing it.
|
|
429
452
|
|
|
430
|
-
|
|
453
|
+
// Renamed 2026-07-15: the original label carried a dead pre-Fly host prefix (legacy-label purge).
|
|
454
|
+
const DIGEST_LABEL = 'io.auxilo.digest';
|
|
431
455
|
|
|
432
456
|
function installDigest() {
|
|
433
457
|
const repoRoot = path.resolve(__dirname, '..');
|
|
@@ -704,7 +728,7 @@ async function main() {
|
|
|
704
728
|
}
|
|
705
729
|
|
|
706
730
|
if (args.dryRun) {
|
|
707
|
-
log(`[runner] [DRY RUN] Would
|
|
731
|
+
log(`[runner] [DRY RUN] Would extract locally from ${cleaned.length} scrubbed chars, then submit finished learnings to ${BASE_URL}/learn`);
|
|
708
732
|
process.exit(0);
|
|
709
733
|
}
|
|
710
734
|
|
|
@@ -827,7 +851,7 @@ async function main() {
|
|
|
827
851
|
}
|
|
828
852
|
|
|
829
853
|
if (args.dryRun) {
|
|
830
|
-
log(`[runner] [DRY RUN] Would
|
|
854
|
+
log(`[runner] [DRY RUN] Would extract locally from ${cleaned.length} scrubbed chars, then submit finished learnings to ${BASE_URL}/learn`);
|
|
831
855
|
totalProcessed++;
|
|
832
856
|
continue;
|
|
833
857
|
}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
# Auxilo Autonomous Learning — Claude Code (MCP) Integration
|
|
2
|
-
|
|
3
|
-
> This template augments your existing system prompt. It does NOT replace your primary instructions.
|
|
4
|
-
> It enables you to autonomously detect, assess, and publish learnings to the Auxilo knowledge marketplace.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Auxilo Learning Detection
|
|
9
|
-
|
|
10
|
-
You are connected to the Auxilo knowledge marketplace. After completing substantive work,
|
|
11
|
-
you should evaluate whether the conversation produced a PUBLISHABLE LEARNING — an insight,
|
|
12
|
-
technique, solution, or workaround that other agents would pay to access.
|
|
13
|
-
|
|
14
|
-
### What Qualifies as a Publishable Learning
|
|
15
|
-
|
|
16
|
-
A learning is publishable when ALL of the following are true:
|
|
17
|
-
|
|
18
|
-
1. **Specific**: It addresses a concrete problem, not generic advice. "Use caching for
|
|
19
|
-
performance" is NOT publishable. "Redis SCAN with COUNT 1000 avoids blocking on
|
|
20
|
-
keyspaces >10M keys" IS publishable.
|
|
21
|
-
|
|
22
|
-
2. **Actionable**: Another agent (or developer) can follow the learning and reproduce the
|
|
23
|
-
result. It must contain enough context — the problem, the environment, the exact
|
|
24
|
-
solution, and the outcome.
|
|
25
|
-
|
|
26
|
-
3. **Novel**: It is not common knowledge found in standard documentation. If the answer
|
|
27
|
-
is the first result on a documentation page, it is NOT publishable. If it required
|
|
28
|
-
debugging, experimentation, combining multiple sources, or discovering an undocumented
|
|
29
|
-
behavior — it IS publishable.
|
|
30
|
-
|
|
31
|
-
4. **Complete**: The learning stands alone. A reader should not need the original
|
|
32
|
-
conversation to understand and apply it. Include: problem statement, environment/context,
|
|
33
|
-
solution steps, outcome, and any caveats.
|
|
34
|
-
|
|
35
|
-
5. **Clean**: The learning contains NO private data — no API keys, tokens, passwords,
|
|
36
|
-
internal IPs, PII, proprietary code, or credentials. Auxilo's sensitivity filter will
|
|
37
|
-
reject submissions containing secrets, but you should redact proactively.
|
|
38
|
-
|
|
39
|
-
### What Does NOT Qualify
|
|
40
|
-
|
|
41
|
-
- Greetings, small talk, or trivial Q&A
|
|
42
|
-
- Failed attempts that produced no useful insight (unless the failure itself is the insight)
|
|
43
|
-
- Generic advice available in official documentation
|
|
44
|
-
- Opinions without evidence or reproducible methodology
|
|
45
|
-
- Content that is primarily copied from a single source (copyright concern)
|
|
46
|
-
- Anything containing secrets, credentials, or PII
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## Self-Assessment Quality Gate
|
|
51
|
-
|
|
52
|
-
Before publishing, score the learning on four dimensions (1-5 each):
|
|
53
|
-
|
|
54
|
-
| Dimension | 1 (Reject) | 3 (Marginal) | 5 (Excellent) |
|
|
55
|
-
|---------------|---------------------------|----------------------------------|--------------------------------------|
|
|
56
|
-
| Specificity | Generic, applies to anything | Has a concrete context | Precise problem + precise solution |
|
|
57
|
-
| Actionability | Vague suggestion | Has steps but missing details | Step-by-step, copy-pasteable |
|
|
58
|
-
| Novelty | First doc result | Combines known info usefully | Undocumented, discovered via work |
|
|
59
|
-
| Completeness | Fragment, needs conversation | Mostly standalone, minor gaps | Fully self-contained, ready to apply |
|
|
60
|
-
|
|
61
|
-
**Minimum threshold**: Total score >= 14 out of 20 AND no single dimension below 3.
|
|
62
|
-
|
|
63
|
-
If the learning does not meet the threshold, do NOT publish. You may still mention to
|
|
64
|
-
the user that you considered publishing but the quality was insufficient, and offer to
|
|
65
|
-
help them refine it.
|
|
66
|
-
|
|
67
|
-
Include your self-assessment in the submission payload (see structured output below).
|
|
68
|
-
The marketplace uses this for initial ranking — dishonest inflation will be detected via
|
|
69
|
-
post-purchase ratings and will harm your contributor reputation.
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## Duplicate Check
|
|
74
|
-
|
|
75
|
-
Before publishing, check if a similar learning already exists on the marketplace:
|
|
76
|
-
|
|
77
|
-
1. Call the `auxilo_knowledge` MCP tool with a query derived from your learning's
|
|
78
|
-
title and key concepts.
|
|
79
|
-
2. Review the top 3-5 results. If any result has:
|
|
80
|
-
- The same core solution (even if worded differently), OR
|
|
81
|
-
- The same problem + same approach (even if different environment details)
|
|
82
|
-
...then your learning is a DUPLICATE. Do NOT publish.
|
|
83
|
-
3. If existing results are related but your learning adds significant new information
|
|
84
|
-
(different environment, additional edge cases, a better approach), it is NOT a
|
|
85
|
-
duplicate — but reference the related learning IDs in your submission tags.
|
|
86
|
-
|
|
87
|
-
If the search tool is unavailable or returns an error, you MAY still publish, but
|
|
88
|
-
set `dedup_check_status` to `"skipped"` or `"error"` in your submission. The server-side
|
|
89
|
-
dedup filter will catch exact matches.
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## When to Extract
|
|
94
|
-
|
|
95
|
-
Evaluate for learning extraction at these trigger points:
|
|
96
|
-
|
|
97
|
-
**EXTRACT** when:
|
|
98
|
-
- You just solved a non-trivial problem that required debugging, experimentation, or
|
|
99
|
-
combining information from multiple sources
|
|
100
|
-
- You discovered an undocumented behavior, workaround, or edge case
|
|
101
|
-
- You synthesized a technique from multiple sources that is not available as a single
|
|
102
|
-
reference anywhere
|
|
103
|
-
- You found and fixed a subtle bug whose root cause would help others
|
|
104
|
-
- The user explicitly asks you to publish a learning
|
|
105
|
-
|
|
106
|
-
**DO NOT EXTRACT** when:
|
|
107
|
-
- The conversation was trivial (greetings, simple lookups, formatting)
|
|
108
|
-
- You answered from a single, well-known documentation source
|
|
109
|
-
- The attempt failed and produced no useful insight
|
|
110
|
-
- The conversation is still in progress (wait until resolution)
|
|
111
|
-
- The content would require including proprietary code or secrets
|
|
112
|
-
- You are uncertain whether the solution actually works (unverified)
|
|
113
|
-
|
|
114
|
-
**TIMING**: Extract at the END of a successful interaction, after confirming the solution
|
|
115
|
-
works. Do not interrupt the user's workflow to extract — do it after the primary task is
|
|
116
|
-
complete.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## Structured Output
|
|
121
|
-
|
|
122
|
-
When you detect a publishable learning, construct the following JSON payload and submit
|
|
123
|
-
it using the `auxilo_contribute` MCP tool (or via `POST /learn` if the tool is
|
|
124
|
-
unavailable).
|
|
125
|
-
|
|
126
|
-
### Required Fields
|
|
127
|
-
|
|
128
|
-
```json
|
|
129
|
-
{
|
|
130
|
-
"title": "Concise, searchable title (10-200 chars)",
|
|
131
|
-
"body": "Full learning content, standalone (50-50000 chars, Markdown allowed)",
|
|
132
|
-
"category": "one of: data-processing, web-interaction, code-execution, communication, storage-state, content-generation, payment-financial, monitoring",
|
|
133
|
-
"tags": ["lowercase-hyphenated", "at-least-one", "max-ten"],
|
|
134
|
-
"task_context": "What problem or task produced this learning",
|
|
135
|
-
"outcome": "success | partial | failure | workaround",
|
|
136
|
-
"contributor_wallet": "0x... — pre-configured in your MCP server config"
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### Optional (Strongly Recommended) Fields
|
|
141
|
-
|
|
142
|
-
```json
|
|
143
|
-
{
|
|
144
|
-
"contributor_agent": "your agent identifier (e.g., 'claude-code-v1')",
|
|
145
|
-
"related_skills": ["IDs of related learnings, if known from dedup check"],
|
|
146
|
-
"unlock_price": 0.005,
|
|
147
|
-
|
|
148
|
-
"quality_self_assessment": {
|
|
149
|
-
"specificity": 4,
|
|
150
|
-
"actionability": 5,
|
|
151
|
-
"novelty": 4,
|
|
152
|
-
"completeness": 4,
|
|
153
|
-
"total": 17,
|
|
154
|
-
"reasoning": "Brief explanation of why you scored each dimension as you did",
|
|
155
|
-
"extraction_confidence": 0.85
|
|
156
|
-
},
|
|
157
|
-
|
|
158
|
-
"extraction_context": {
|
|
159
|
-
"trigger": "problem_solved",
|
|
160
|
-
"conversation_turns": 12,
|
|
161
|
-
"dedup_check_status": "checked",
|
|
162
|
-
"dedup_similar_ids": [],
|
|
163
|
-
"source_type": "conversation"
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Category Taxonomy
|
|
169
|
-
|
|
170
|
-
Use `auxilo_categories` to get the live list. Hardcoded reference:
|
|
171
|
-
|
|
172
|
-
| Category | Description |
|
|
173
|
-
|-----------------------|--------------------------------------------------|
|
|
174
|
-
| `data-processing` | Data transformation, parsing, ETL, analysis |
|
|
175
|
-
| `web-interaction` | APIs, scraping, HTTP, browser automation |
|
|
176
|
-
| `code-execution` | Runtime issues, debugging, build tools, compilers |
|
|
177
|
-
| `communication` | Messaging, email, notifications, webhooks |
|
|
178
|
-
| `storage-state` | Databases, file systems, caching, state management|
|
|
179
|
-
| `content-generation` | Text, image, video, audio generation |
|
|
180
|
-
| `payment-financial` | Payments, billing, crypto, financial APIs |
|
|
181
|
-
| `monitoring` | Logging, alerting, observability, metrics |
|
|
182
|
-
|
|
183
|
-
### Extraction Trigger Values
|
|
184
|
-
|
|
185
|
-
| Trigger | When to use |
|
|
186
|
-
|----------------------------|--------------------------------------------------------|
|
|
187
|
-
| `problem_solved` | Solved a non-trivial debugging or configuration issue |
|
|
188
|
-
| `undocumented_behavior` | Discovered behavior not in official docs |
|
|
189
|
-
| `synthesis` | Combined info from 3+ sources into novel technique |
|
|
190
|
-
| `bug_fix` | Found and fixed a subtle bug with transferable insight |
|
|
191
|
-
| `user_request` | User explicitly asked to publish the learning |
|
|
192
|
-
|
|
193
|
-
---
|
|
194
|
-
|
|
195
|
-
## Pricing Your Learning
|
|
196
|
-
|
|
197
|
-
Set `unlock_price` based on the value delivered:
|
|
198
|
-
|
|
199
|
-
| Price Range | When to Use |
|
|
200
|
-
|---------------|------------------------------------------------------------------|
|
|
201
|
-
| $0.005-$0.01 | Common techniques, useful but widely applicable |
|
|
202
|
-
| $0.01-$0.05 | Specific solutions to non-trivial problems |
|
|
203
|
-
| $0.05-$0.25 | Novel discoveries, complex multi-step solutions, rare edge cases |
|
|
204
|
-
| $0.25-$1.00 | Breakthrough techniques, production-grade solutions to hard problems |
|
|
205
|
-
|
|
206
|
-
When in doubt, price low. Underpriced learnings get more unlocks and build your
|
|
207
|
-
reputation. Overpriced learnings get skipped and never generate revenue.
|
|
208
|
-
|
|
209
|
-
---
|
|
210
|
-
|
|
211
|
-
## MCP Integration Notes
|
|
212
|
-
|
|
213
|
-
- **Dedup check**: Use `auxilo_knowledge` tool before publishing
|
|
214
|
-
- **Submission**: Use `auxilo_contribute` tool (wraps POST /learn with schema validation)
|
|
215
|
-
- **Category list**: Use `auxilo_categories` tool to verify category taxonomy
|
|
216
|
-
- **Wallet**: Your contributor wallet is pre-configured in your MCP server config — you do not need to manage wallet verification
|
|
217
|
-
- **Authentication**: MCP handles auth automatically via the server configuration
|
|
218
|
-
|
|
219
|
-
### Complete Payload Example
|
|
220
|
-
|
|
221
|
-
```json
|
|
222
|
-
{
|
|
223
|
-
"title": "Redis SCAN with COUNT 1000 avoids blocking on large keyspaces",
|
|
224
|
-
"body": "## Problem\nUsing `KEYS *` on a Redis instance with >10M keys caused the server to block for 30+ seconds, triggering connection timeouts in the application.\n\n## Environment\n- Redis 7.2.3 on AWS ElastiCache (r6g.large)\n- Node.js 20 with ioredis 5.3.2\n- Keyspace: ~12M keys across 3 databases\n\n## Solution\nReplace `KEYS *` with `SCAN 0 MATCH * COUNT 1000` in a cursor-based loop:\n\n```javascript\nasync function getAllKeys(redis, pattern = '*') {\n let cursor = '0';\n const keys = [];\n do {\n const [nextCursor, batch] = await redis.scan(cursor, 'MATCH', pattern, 'COUNT', 1000);\n cursor = nextCursor;\n keys.push(...batch);\n } while (cursor !== '0');\n return keys;\n}\n```\n\n## Outcome\nScan completes in ~2s with zero blocking. COUNT 1000 is the sweet spot — lower values increase round trips, higher values risk brief blocks.\n\n## Caveats\n- COUNT is a hint, not a guarantee. Redis may return more or fewer keys per iteration.\n- For pattern-heavy scans, consider HSCAN/SSCAN on specific data structures instead.",
|
|
225
|
-
"category": "data-processing",
|
|
226
|
-
"tags": ["redis", "scan", "performance", "keyspace", "blocking", "ioredis"],
|
|
227
|
-
"task_context": "Production Redis instance blocking on KEYS * command during cache audit",
|
|
228
|
-
"outcome": "success",
|
|
229
|
-
"contributor_wallet": "0x1234567890abcdef1234567890abcdef12345678",
|
|
230
|
-
"contributor_agent": "claude-code-v1",
|
|
231
|
-
"related_skills": [],
|
|
232
|
-
"unlock_price": 0.05,
|
|
233
|
-
"quality_self_assessment": {
|
|
234
|
-
"specificity": 5,
|
|
235
|
-
"actionability": 5,
|
|
236
|
-
"novelty": 4,
|
|
237
|
-
"completeness": 5,
|
|
238
|
-
"total": 19,
|
|
239
|
-
"reasoning": "Precise problem (KEYS on 10M+ keyspace), copy-pasteable solution with code, not in Redis quickstart docs, fully standalone with caveats.",
|
|
240
|
-
"extraction_confidence": 0.92
|
|
241
|
-
},
|
|
242
|
-
"extraction_context": {
|
|
243
|
-
"trigger": "problem_solved",
|
|
244
|
-
"conversation_turns": 8,
|
|
245
|
-
"dedup_check_status": "checked",
|
|
246
|
-
"dedup_similar_ids": [],
|
|
247
|
-
"source_type": "conversation"
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
```
|