@prismer/runtime 2.0.8 → 2.2.55

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +3430 -0
  2. package/README.md +34 -12
  3. package/apc/skills/FIELD-DICTIONARY.md +111 -0
  4. package/apc/skills/bug-reproduce/SKILL.md +150 -0
  5. package/apc/skills/bug-reproduce/skill.json +96 -0
  6. package/apc/skills/code-review/SKILL.md +198 -0
  7. package/apc/skills/code-review/skill.json +124 -0
  8. package/apc/skills/design-review/SKILL.md +122 -0
  9. package/apc/skills/design-review/skill.json +88 -0
  10. package/apc/skills/doc-sync/SKILL.md +168 -0
  11. package/apc/skills/doc-sync/skill.json +81 -0
  12. package/apc/skills/env-doctor/SKILL.md +194 -0
  13. package/apc/skills/env-doctor/skill.json +209 -0
  14. package/apc/skills/git-ops/SKILL.md +189 -0
  15. package/apc/skills/git-ops/skill.json +94 -0
  16. package/apc/skills/impact-trace/SKILL.md +168 -0
  17. package/apc/skills/impact-trace/skill.json +104 -0
  18. package/apc/skills/observability/SKILL.md +195 -0
  19. package/apc/skills/observability/skill.json +116 -0
  20. package/apc/skills/release-db-config-sync/SKILL.md +186 -0
  21. package/apc/skills/release-db-config-sync/skill.json +109 -0
  22. package/apc/skills/release-ota-promote/SKILL.md +195 -0
  23. package/apc/skills/release-ota-promote/skill.json +176 -0
  24. package/apc/skills/release-preflight/SKILL.md +174 -0
  25. package/apc/skills/release-preflight/skill.json +175 -0
  26. package/apc/skills/release-rollback/SKILL.md +214 -0
  27. package/apc/skills/release-rollback/skill.json +230 -0
  28. package/apc/skills/release-tag/SKILL.md +194 -0
  29. package/apc/skills/release-tag/skill.json +94 -0
  30. package/apc/skills/releasing-prod/SKILL.md +49 -0
  31. package/apc/skills/releasing-test/SKILL.md +135 -0
  32. package/apc/skills/sdk-release/SKILL.md +200 -0
  33. package/apc/skills/spec-intake/SKILL.md +169 -0
  34. package/apc/skills/spec-intake/skill.json +93 -0
  35. package/apc/skills/test-result-feedback/SKILL.md +239 -0
  36. package/apc/skills/test-result-feedback/skill.json +193 -0
  37. package/apc/skills/test-runner/SKILL.md +169 -0
  38. package/apc/skills/test-runner/skill.json +103 -0
  39. package/apc/skills/ui-align/SKILL.md +209 -0
  40. package/apc/skills/ui-align/skill.json +114 -0
  41. package/apc/skills/ui-canvas/SKILL.md +148 -0
  42. package/apc/skills/ui-canvas/skill.json +127 -0
  43. package/built-in-skills/agent-coordination/SKILL.md +59 -37
  44. package/built-in-skills/agent-meta/SKILL.md +1 -0
  45. package/built-in-skills/assets/SKILL.md +8 -6
  46. package/built-in-skills/browser-use/SKILL.md +93 -0
  47. package/built-in-skills/canvas-design/SKILL.md +1 -0
  48. package/built-in-skills/claim-agent-ownership/SKILL.md +3 -2
  49. package/built-in-skills/claude-api/SKILL.md +1 -0
  50. package/built-in-skills/codebase-design/DEEPENING.md +37 -0
  51. package/built-in-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  52. package/built-in-skills/codebase-design/LICENSE +21 -0
  53. package/built-in-skills/codebase-design/SKILL.md +116 -0
  54. package/built-in-skills/conversation-compaction/SKILL.md +114 -0
  55. package/built-in-skills/council-creator/SKILL.md +426 -0
  56. package/built-in-skills/diagnosing-bugs/LICENSE +21 -0
  57. package/built-in-skills/diagnosing-bugs/SKILL.md +136 -0
  58. package/built-in-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
  59. package/built-in-skills/doc-coauthoring/SKILL.md +1 -0
  60. package/built-in-skills/document-generation/SKILL.md +105 -0
  61. package/built-in-skills/domain-modeling/ADR-FORMAT.md +47 -0
  62. package/built-in-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  63. package/built-in-skills/domain-modeling/LICENSE +21 -0
  64. package/built-in-skills/domain-modeling/SKILL.md +76 -0
  65. package/built-in-skills/frontend-design/SKILL.md +1 -0
  66. package/built-in-skills/human-approval/SKILL.md +17 -2
  67. package/built-in-skills/image-generate/SKILL.md +103 -302
  68. package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +289 -0
  69. package/built-in-skills/ingest/SKILL.md +13 -45
  70. package/built-in-skills/internal-comms/SKILL.md +1 -0
  71. package/built-in-skills/liteparse/SKILL.md +130 -110
  72. package/built-in-skills/mcp-builder/SKILL.md +1 -0
  73. package/built-in-skills/memory/SKILL.md +420 -55
  74. package/built-in-skills/memory-dream/SKILL.md +339 -0
  75. package/built-in-skills/office-artifacts/SKILL.md +17 -4
  76. package/built-in-skills/okr/SKILL.md +154 -0
  77. package/built-in-skills/persona/SKILL.md +81 -0
  78. package/built-in-skills/persona-generator/SKILL.md +296 -0
  79. package/built-in-skills/pkf-svg/SKILL.md +253 -0
  80. package/built-in-skills/pkf-writing/SKILL.md +236 -0
  81. package/built-in-skills/prismer-im-collab/SKILL.md +26 -6
  82. package/built-in-skills/proactivity/SKILL.md +84 -0
  83. package/built-in-skills/remotion/SKILL.md +431 -0
  84. package/built-in-skills/role-builder/SKILL.md +203 -0
  85. package/built-in-skills/role-builder/scripts/author-role.mjs +334 -0
  86. package/built-in-skills/role-builder/scripts/ingest-role.mjs +223 -0
  87. package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +290 -0
  88. package/built-in-skills/role-builder/scripts/operation-harness.mjs +267 -0
  89. package/built-in-skills/skill-authoring/SKILL.md +110 -100
  90. package/built-in-skills/skill-authoring/skill.json +3 -3
  91. package/built-in-skills/skill-builder/SKILL.md +171 -0
  92. package/built-in-skills/skill-builder/scripts/ingest.mjs +265 -0
  93. package/built-in-skills/skill-creator/SKILL.md +165 -423
  94. package/built-in-skills/skill-creator/references/external-library-import.md +110 -0
  95. package/built-in-skills/skill-creator/scripts/import-library.mjs +475 -0
  96. package/built-in-skills/slack-gif-creator/SKILL.md +20 -0
  97. package/built-in-skills/tasks/SKILL.md +38 -23
  98. package/built-in-skills/tdd/LICENSE +21 -0
  99. package/built-in-skills/tdd/SKILL.md +110 -0
  100. package/built-in-skills/tdd/mocking.md +59 -0
  101. package/built-in-skills/tdd/refactoring.md +10 -0
  102. package/built-in-skills/tdd/tests.md +61 -0
  103. package/built-in-skills/team/SKILL.md +2 -1
  104. package/built-in-skills/web-artifacts-builder/SKILL.md +1 -0
  105. package/built-in-skills/webapp-testing/SKILL.md +1 -0
  106. package/built-in-skills/wechat-pay/SKILL.md +59 -0
  107. package/dist/cli.cjs +71872 -19960
  108. package/dist/cli.js +71803 -19846
  109. package/dist/index.cjs +72010 -19966
  110. package/dist/index.d.cts +4258 -712
  111. package/dist/index.d.ts +4258 -712
  112. package/dist/index.js +72156 -20118
  113. package/package.json +37 -6
  114. package/plugins/memory/prismer/__init__.py +1211 -0
  115. package/plugins/memory/prismer/plugin.yaml +8 -0
  116. package/plugins/memory/prismer/tool-schemas.generated.json +249 -0
  117. package/plugins/tools/prismer-recall/__init__.py +282 -0
  118. package/plugins/tools/prismer-recall/plugin.yaml +15 -0
  119. package/built-in-skills/memory-curation/SKILL.md +0 -135
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFile } from 'node:child_process';
4
+ import { createHash } from 'node:crypto';
5
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
6
+ import { homedir } from 'node:os';
7
+ import { dirname, extname, join, resolve } from 'node:path';
8
+ import { promisify } from 'node:util';
9
+
10
+ const execFileAsync = promisify(execFile);
11
+ const ALLOWED_SIZES = new Set(['256x256', '512x512', '1024x1024', '1792x1024', '1024x1792']);
12
+
13
+ function usage() {
14
+ return [
15
+ 'Usage: node scripts/generate-and-deliver.mjs --prompt <text> [options]',
16
+ '',
17
+ 'Options:',
18
+ ' --size <WxH> Default: 1024x1024',
19
+ ' --model <id> Default: IMAGE_GEN_MODEL or deployment priority',
20
+ ' --output <path> Default: $PRISMER_ARTIFACTS_DIR/generated-<sha8>.<ext> (or cwd)',
21
+ ' --base-url <url> Default: Prismer runtime env/config',
22
+ ' --help',
23
+ ].join('\n');
24
+ }
25
+
26
+ function parseArgs(argv) {
27
+ const out = { size: '1024x1024' };
28
+ for (let i = 0; i < argv.length; i += 1) {
29
+ const arg = argv[i];
30
+ if (arg === '--help' || arg === '-h') out.help = true;
31
+ else if (arg === '--prompt') out.prompt = argv[++i];
32
+ else if (arg === '--size') out.size = argv[++i];
33
+ else if (arg === '--model') out.model = argv[++i];
34
+ else if (arg === '--output') out.output = argv[++i];
35
+ else if (arg === '--base-url') out.baseUrl = argv[++i];
36
+ else throw new Error(`Unknown argument: ${arg}`);
37
+ }
38
+ if (!out.help && (typeof out.prompt !== 'string' || out.prompt.trim().length === 0)) {
39
+ throw new Error('--prompt is required');
40
+ }
41
+ if (!out.help && out.prompt.length > 4000) throw new Error('--prompt must be at most 4000 characters');
42
+ if (!out.help && !ALLOWED_SIZES.has(out.size)) throw new Error(`Unsupported --size: ${out.size}`);
43
+ return out;
44
+ }
45
+
46
+ async function readRuntimeConfig() {
47
+ const root = process.env.PRISMER_HOME || join(homedir(), '.prismer');
48
+ try {
49
+ const raw = await readFile(join(root, 'config.toml'), 'utf8');
50
+ const value = (keys) => {
51
+ for (const key of keys) {
52
+ const match = raw.match(new RegExp(`^${key}\\s*=\\s*["']([^"']+)["']`, 'm'));
53
+ if (match?.[1]) return match[1];
54
+ }
55
+ return undefined;
56
+ };
57
+ return {
58
+ baseUrl: value(['cloud_api_base', 'base_url']),
59
+ apiKey: value(['api_key']),
60
+ };
61
+ } catch {
62
+ return {};
63
+ }
64
+ }
65
+
66
+ async function resolveAuth(args) {
67
+ const config = await readRuntimeConfig();
68
+ const baseUrl =
69
+ args.baseUrl ||
70
+ process.env.PRISMER_CLOUD_BASE ||
71
+ process.env.PRISMER_BASE_URL ||
72
+ process.env.CLOUD_API_BASE ||
73
+ process.env.PRISMER_CLOUD_API_BASE ||
74
+ config.baseUrl;
75
+ const apiKey = process.env.PRISMER_API_KEY || config.apiKey;
76
+ if (!baseUrl) throw new Error('Missing Prismer cloud base URL (set PRISMER_CLOUD_BASE or configure cloud_api_base)');
77
+ if (!apiKey) throw new Error('Missing PRISMER_API_KEY and no api_key was found in config.toml');
78
+ return { baseUrl: baseUrl.replace(/\/$/, ''), apiKey };
79
+ }
80
+
81
+ async function readJson(response) {
82
+ const text = await response.text();
83
+ if (!text) return {};
84
+ try {
85
+ return JSON.parse(text);
86
+ } catch {
87
+ throw new Error(`Cloud returned non-JSON status=${response.status}: ${text.slice(0, 200)}`);
88
+ }
89
+ }
90
+
91
+ function errorDetail(status, body) {
92
+ const error = body?.error;
93
+ const code = typeof error?.code === 'string' ? error.code : typeof error?.type === 'string' ? error.type : '';
94
+ const message = typeof error?.message === 'string' ? error.message : typeof error === 'string' ? error : `HTTP ${status}`;
95
+ return { status, code, message };
96
+ }
97
+
98
+ function canFallback(error) {
99
+ if (error.status === 402) return false;
100
+ return (
101
+ error.status === 404 ||
102
+ error.status === 429 ||
103
+ error.status >= 500 ||
104
+ ['model_not_found', 'rate_limit', 'rate_limit_exceeded', 'insufficient_quota'].includes(error.code)
105
+ );
106
+ }
107
+
108
+ function normalizeModel(model) {
109
+ return {
110
+ id: model.id,
111
+ sizes: Array.isArray(model.sizes) ? model.sizes.filter((size) => typeof size === 'string') : null,
112
+ };
113
+ }
114
+
115
+ function supportsSize(model, size) {
116
+ return model.sizes === null || model.sizes.length === 0 || model.sizes.includes(size);
117
+ }
118
+
119
+ async function discoverModels(auth, preferred, size) {
120
+ const response = await fetch(`${auth.baseUrl}/api/v1/image-models`, {
121
+ headers: { Authorization: `Bearer ${auth.apiKey}` },
122
+ signal: AbortSignal.timeout(30_000),
123
+ });
124
+ const body = await readJson(response);
125
+ if (!response.ok || !Array.isArray(body.data)) {
126
+ const detail = errorDetail(response.status, body);
127
+ if (preferred) return [{ id: preferred, sizes: null }];
128
+ throw new Error(`Image model discovery failed: ${detail.status} ${detail.code} ${detail.message}`.trim());
129
+ }
130
+ const discovered = body.data
131
+ .filter((model) => model && typeof model.id === 'string')
132
+ .sort((a, b) => Number(a.priority ?? 999) - Number(b.priority ?? 999))
133
+ .map(normalizeModel);
134
+ const preferredModel = preferred ? discovered.find((model) => model.id === preferred) : undefined;
135
+ const candidates = [
136
+ ...(preferred && !preferredModel ? [{ id: preferred, sizes: null }] : []),
137
+ ...(preferredModel ? [preferredModel] : []),
138
+ ...discovered,
139
+ ].filter((model) => supportsSize(model, size));
140
+ const unique = candidates.filter((model, index) => candidates.findIndex((item) => item.id === model.id) === index);
141
+ if (unique.length === 0) {
142
+ const available = discovered
143
+ .map((model) => `${model.id}=[${model.sizes?.join(',') || 'unknown'}]`)
144
+ .join(', ');
145
+ throw new Error(`No image model supports size=${size}; available: ${available || 'none'}`);
146
+ }
147
+ return unique;
148
+ }
149
+
150
+ async function generate(auth, args, models) {
151
+ const failures = [];
152
+ for (const candidate of models) {
153
+ const model = candidate.id;
154
+ const response = await fetch(`${auth.baseUrl}/api/v1/images/generations`, {
155
+ method: 'POST',
156
+ headers: {
157
+ Authorization: `Bearer ${auth.apiKey}`,
158
+ 'Content-Type': 'application/json',
159
+ },
160
+ body: JSON.stringify({
161
+ prompt: args.prompt,
162
+ model,
163
+ size: args.size,
164
+ n: 1,
165
+ response_format: 'b64_json',
166
+ }),
167
+ signal: AbortSignal.timeout(180_000),
168
+ });
169
+ const body = await readJson(response);
170
+ if (!response.ok) {
171
+ const detail = { model, ...errorDetail(response.status, body) };
172
+ failures.push(detail);
173
+ if (canFallback(detail)) {
174
+ process.stderr.write(`[image-generate] model=${model} failed (${detail.status} ${detail.code || 'error'}); trying fallback\n`);
175
+ continue;
176
+ }
177
+ throw new Error(`Image generation failed: model=${model} status=${detail.status} code=${detail.code || '-'} message=${detail.message}`);
178
+ }
179
+ const item = body?.data?.[0];
180
+ if (typeof item?.b64_json === 'string' && item.b64_json.length > 0) {
181
+ return { bytes: Buffer.from(item.b64_json, 'base64'), model };
182
+ }
183
+ if (typeof item?.url === 'string' && item.url.length > 0) {
184
+ return { bytes: await downloadImage(item.url), model };
185
+ }
186
+ throw new Error(`Image generation returned no bytes or URL for model=${model}`);
187
+ }
188
+ throw new Error(
189
+ `All image models failed: ${failures.map((failure) => `${failure.model}:${failure.status}/${failure.code || 'error'}`).join(', ')}`,
190
+ );
191
+ }
192
+
193
+ async function downloadImage(url) {
194
+ if (url.startsWith('data:')) {
195
+ const match = url.match(/^data:[^;,]+;base64,(.+)$/s);
196
+ if (!match) throw new Error('Unsupported image data URL');
197
+ return Buffer.from(match[1], 'base64');
198
+ }
199
+ const response = await fetch(url, { signal: AbortSignal.timeout(60_000) });
200
+ if (!response.ok) throw new Error(`Generated image download failed: HTTP ${response.status}`);
201
+ return Buffer.from(await response.arrayBuffer());
202
+ }
203
+
204
+ function detectImage(bytes) {
205
+ if (bytes.subarray(0, 8).equals(Buffer.from('89504e470d0a1a0a', 'hex'))) return { extension: '.png', mediaType: 'image/png' };
206
+ if (bytes.subarray(0, 3).equals(Buffer.from('ffd8ff', 'hex'))) return { extension: '.jpg', mediaType: 'image/jpeg' };
207
+ if (bytes.subarray(0, 4).toString('ascii') === 'RIFF' && bytes.subarray(8, 12).toString('ascii') === 'WEBP') {
208
+ return { extension: '.webp', mediaType: 'image/webp' };
209
+ }
210
+ throw new Error('Generated bytes are not a supported PNG, JPEG, or WebP image');
211
+ }
212
+
213
+ async function saveImage(args, bytes) {
214
+ const detected = detectImage(bytes);
215
+ const sha = createHash('sha256').update(bytes).digest('hex');
216
+ const generatedName = `generated-${sha.slice(0, 8)}${detected.extension}`;
217
+ const output = args.output
218
+ ? resolve(args.output)
219
+ : resolve(process.env.PRISMER_ARTIFACTS_DIR || process.cwd(), generatedName);
220
+ if (args.output && extname(output).toLowerCase() !== detected.extension) {
221
+ throw new Error(`--output extension must match generated ${detected.mediaType} bytes (${detected.extension})`);
222
+ }
223
+ await mkdir(dirname(output), { recursive: true });
224
+ await writeFile(output, bytes);
225
+ return { output, sha, mediaType: detected.mediaType };
226
+ }
227
+
228
+ async function deliver(output) {
229
+ const cloudBin = process.env.PRISMER_CLOUD_BIN || 'cloud';
230
+ let stdout;
231
+ try {
232
+ ({ stdout } = await execFileAsync(cloudBin, ['deliver', output, '--json'], {
233
+ encoding: 'utf8',
234
+ timeout: 120_000,
235
+ maxBuffer: 1024 * 1024,
236
+ }));
237
+ } catch (error) {
238
+ const detail = typeof error?.stderr === 'string' ? error.stderr.trim() : error.message;
239
+ throw new Error(`cloud deliver failed: ${detail}`);
240
+ }
241
+ let result;
242
+ try {
243
+ result = JSON.parse(stdout);
244
+ } catch {
245
+ throw new Error(`cloud deliver returned non-JSON output: ${stdout.slice(0, 200)}`);
246
+ }
247
+ if (result?.ok !== true) throw new Error(`cloud deliver rejected the image: ${result?.error || 'unknown error'}`);
248
+ if (result.status === 202 || result.queued === true) return { status: 'queued', receipt: result };
249
+ if (typeof result.assetId !== 'string' || result.assetId.length === 0) {
250
+ throw new Error('cloud deliver returned ok without an assetId or queued receipt');
251
+ }
252
+ if (result.ridesReply === false) return { status: 'uploaded-unattached', receipt: result };
253
+ return { status: 'delivered', receipt: result };
254
+ }
255
+
256
+ async function main() {
257
+ const args = parseArgs(process.argv.slice(2));
258
+ if (args.help) {
259
+ process.stdout.write(`${usage()}\n`);
260
+ return;
261
+ }
262
+ const auth = await resolveAuth(args);
263
+ const preferred = args.model || process.env.IMAGE_GEN_MODEL;
264
+ const models = await discoverModels(auth, preferred, args.size);
265
+ if (models.length === 0) throw new Error('No image generation models are available');
266
+ const generated = await generate(auth, args, models);
267
+ const saved = await saveImage(args, generated.bytes);
268
+ const delivery = await deliver(saved.output);
269
+ if (delivery.status === 'queued') {
270
+ process.stdout.write(
271
+ `[image-generate] queued file=${saved.output} model=${generated.model} size=${args.size} sha=${saved.sha.slice(0, 12)}; upload pending reconnect\n`,
272
+ );
273
+ return;
274
+ }
275
+ if (delivery.status === 'uploaded-unattached') {
276
+ process.stdout.write(
277
+ `[image-generate] uploaded-unattached file=${saved.output} assetId=${delivery.receipt.assetId} model=${generated.model} size=${args.size} sha=${saved.sha.slice(0, 12)}; no reply dispatch was available\n`,
278
+ );
279
+ return;
280
+ }
281
+ process.stdout.write(
282
+ `[image-generate] delivered file=${saved.output} assetId=${delivery.receipt.assetId} model=${generated.model} size=${args.size} sha=${saved.sha.slice(0, 12)}\n`,
283
+ );
284
+ }
285
+
286
+ main().catch((error) => {
287
+ process.stderr.write(`[image-generate] ${error instanceof Error ? error.message : String(error)}\n`);
288
+ process.exitCode = 1;
289
+ });
@@ -1,25 +1,28 @@
1
1
  ---
2
2
  name: ingest
3
- description: Turn external URLs and documents into LLM-ready content — load + cache web pages (HQCC compression) and OCR PDFs/images to Markdown. Use whenever the user gives a URL, asks you to read a webpage, or attaches a PDF/scan that needs to be parsed before reasoning. Executes via the `cloud load`, `cloud search`, and `cloud parse` CLIs.
3
+ scope: common
4
+ description: Turn external web URLs into LLM-ready content — load + cache web pages (HQCC compression) and search the web. Use whenever the user gives a URL, asks you to read a webpage, or wants top-K pages on a topic. Executes via the `cloud load` and `cloud search` CLIs. For local document parsing (PDF text + OCR), use the `liteparse` skill instead.
4
5
  ---
5
6
 
6
7
  # Ingest
7
8
 
8
- Use this skill to **bring external content into the LLM context window** without copy-pasting raw HTML or burning tokens on uncompressed prose. Two paths:
9
+ Use this skill to **bring external web content into the LLM context window** without copy-pasting raw HTML or burning tokens on uncompressed prose:
9
10
 
10
11
  - **Web content** → `cloud load` / `cloud search` → returns HQCC (a compressed, LLM-optimized form). Cache hits are free.
11
- - **Documents (PDF, images)** → `cloud parse` → OCR to Markdown. Two modes: `fast` (digital PDFs, clean images) and `hires` (scans, handwriting).
12
+
13
+ > **Local documents (PDF text extraction + OCR) are handled by the `liteparse` skill**, not here — it's a local-first, zero-network tool with Tesseract + PDFium bundled. `ingest` covers web URLs only.
14
+
15
+ > If your runtime registers the `workspace_web_search` / `web_load` tools (Hermes agents do), prefer them over the CLI — same workspace-billed cloud lane (`/api/context/load`). Never script HTTP via `execute_code`/subprocess for web research.
12
16
 
13
17
  ## When to use
14
18
 
15
19
  - The user pastes a URL or asks "what does this page say".
16
20
  - The user asks to research a topic ("AI agent frameworks 2025") — use `search` to fetch top-K relevant pages.
17
- - The user attaches a PDF or image and the next step requires reading its contents.
18
21
  - A task description contains URLs that need to be resolved into actual content before the assignee can act.
19
22
 
20
- ## CLI Reference
23
+ > Attached PDFs / images / scans → use the `liteparse` skill (local-first PDF text + OCR), not `ingest`.
21
24
 
22
- ### Web content
25
+ ## CLI Reference
23
26
 
24
27
  ```bash
25
28
  # Single URL → HQCC
@@ -37,23 +40,6 @@ cloud search "topic" -k 10
37
40
  cloud context save https://example.com "compressed content"
38
41
  ```
39
42
 
40
- ### Documents (OCR)
41
-
42
- ```bash
43
- # Fast mode — digital PDFs, clean images
44
- cloud parse https://example.com/paper.pdf
45
-
46
- # Hi-res — scans, handwriting, complex layouts
47
- cloud parse https://example.com/scan.pdf -m hires
48
-
49
- # Async — long parses return a task id; poll until ready
50
- cloud parse <url> --async # → returns parseTaskId
51
- cloud parse-status <parseTaskId> # check progress
52
- cloud parse-result <parseTaskId> # fetch finished markdown
53
- ```
54
-
55
- Supported parse formats: PDF, PNG, JPG, TIFF, BMP, GIF, WEBP.
56
-
57
43
  ## Workflow
58
44
 
59
45
  ### For web URLs
@@ -63,14 +49,6 @@ Supported parse formats: PDF, PNG, JPG, TIFF, BMP, GIF, WEBP.
63
49
  3. Run `cloud load` / `cloud search` and capture: source URLs, titles, cache status, cost.
64
50
  4. Base downstream reasoning **only on the returned content**. If a load failed, say so; don't pretend you read it.
65
51
 
66
- ### For documents
67
-
68
- 1. Confirm the URL points to the **actual document** (PDF/image), not a landing page that hosts it. If unsure, try `cloud load` first to see what's at that URL.
69
- 2. Start with `fast` mode for digital PDFs and clean images. Switch to `hires` when fidelity matters (scans, handwriting, dense tables).
70
- 3. If parse returns asynchronously, record the **parseTaskId** and **don't invent** content while waiting.
71
- 4. When the result returns, capture page count, cost, and any parse warnings.
72
- 5. Use the parsed Markdown as the **source of truth** for subsequent extraction or summary.
73
-
74
52
  ## Operating Rules
75
53
 
76
54
  ### Load / Search
@@ -80,14 +58,7 @@ Supported parse formats: PDF, PNG, JPG, TIFF, BMP, GIF, WEBP.
80
58
  - Don't claim to have read a source until the load **succeeds**. If it fails (404, blocked, timeout), report the failed URL and continue only with clearly stated assumptions or ask for a better source.
81
59
  - `--format raw` costs more tokens. Only use when the user needs exact wording (legal text, code snippets, tables that compress badly).
82
60
  - For batch loads, the service runs them concurrently up to a limit; you don't need to throttle yourself.
83
-
84
- ### Parse
85
-
86
- - Don't parse **private or access-controlled documents** unless the user explicitly intended to share that source.
87
- - Prefer `cloud load` for **normal web pages**. Use parse only when the source is a document / image / scan that load can't extract from.
88
- - For large or expensive parses (long PDFs in hi-res), explain the tradeoff before running if the user didn't explicitly ask for full fidelity.
89
- - If the result is **incomplete** (truncated, low confidence on key pages), ask for a clearer source or escalate to `hires` before drawing firm conclusions.
90
- - Async parse is the right call for documents >50 pages or hi-res scans. Sync mode will time out on these.
61
+ - For a document / image / scan (not a web page), hand off to the `liteparse` skill — `ingest` does not do OCR or PDF extraction.
91
62
 
92
63
  ## Output reporting
93
64
 
@@ -95,11 +66,8 @@ After load/search:
95
66
  - One-line summary per source: `<title> · <url> · cache_hit | fresh · <cost>`
96
67
  - Then proceed with the user's actual question, citing the source by URL.
97
68
 
98
- After parse:
99
- - `Parsed <filename>: <pageCount> pages, <cost> credits, mode=<fast|hires>`
100
- - If async: `Parse queued as <parseTaskId>; poll with cloud parse-status`
101
- - Use the markdown body for the next step; don't dump the whole thing in chat unless the user asked.
102
-
103
69
  ## Backing capabilities (D22 mapping)
104
70
 
105
- Replaces these v1.x built-in skills: `context-load`, `parse-document`.
71
+ Replaces the v1.x built-in skill `context-load`. Local document OCR /
72
+ extraction (formerly `parse-document`, backed by the now-retired
73
+ `parser.prismer.dev` service) moved to the local-first `liteparse` skill.
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: internal-comms
3
+ scope: common
3
4
  description: A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).
4
5
  license: Complete terms in LICENSE.txt
5
6
  ---