@skhema/cli 0.4.3 → 0.4.5
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/dist/commands/document.d.ts +10 -0
- package/dist/commands/document.d.ts.map +1 -0
- package/dist/commands/document.js +122 -0
- package/dist/lib/api/command-helpers.d.ts.map +1 -1
- package/dist/lib/api/command-helpers.js +2 -1
- package/dist/lib/api/passthrough.d.ts.map +1 -1
- package/dist/lib/api/passthrough.js +12 -3
- package/dist/lib/api/payload.d.ts.map +1 -1
- package/dist/lib/api/payload.js +2 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +2 -0
- package/package.json +2 -2
- package/skills/.manifest.json +8 -10
- package/skills/skhema-calibrate/SKILL.md +90 -0
- package/skills/skhema-calibrate/references/assumptions.md +77 -0
- package/skills/skhema-calibrate/references/coherence.md +95 -0
- package/skills/skhema-calibrate/references/freshness.md +81 -0
- package/skills/skhema-calibrate/references/language.md +74 -0
- package/skills/skhema-communicate/SKILL.md +94 -0
- package/skills/skhema-communicate/references/audience-adaptation.md +103 -0
- package/skills/skhema-communicate/references/board-update.md +93 -0
- package/skills/skhema-communicate/references/decision-brief.md +93 -0
- package/skills/skhema-communicate/references/team-brief.md +91 -0
- package/skills/skhema-compose/SKILL.md +98 -0
- package/skills/skhema-compose/references/assemble.md +119 -0
- package/skills/skhema-compose/references/decompose.md +104 -0
- package/skills/skhema-compose/references/metrics-tree.md +101 -0
- package/skills/skhema-compose/references/options.md +109 -0
- package/skills/skhema-frame/SKILL.md +86 -0
- package/skills/skhema-frame/references/challenge.md +84 -0
- package/skills/skhema-frame/references/decision.md +92 -0
- package/skills/skhema-frame/references/outcome.md +82 -0
- package/skills/skhema-frame/references/policy.md +82 -0
- package/skills/skhema-frame/references/scope.md +79 -0
- package/skills/skhema-operate/SKILL.md +107 -0
- package/skills/skhema-operate/references/auth.md +110 -0
- package/skills/skhema-operate/references/author-elements.md +158 -0
- package/skills/skhema-operate/references/navigate.md +110 -0
- package/skills/skhema-operate/references/surfaces.md +67 -0
- package/skills/skhema-operate/references/validation-loop.md +84 -0
- package/skills/skhema-pressure-test/SKILL.md +107 -0
- package/skills/skhema-pressure-test/references/decision-grill.md +127 -0
- package/skills/skhema-pressure-test/references/full-grill.md +118 -0
- package/skills/skhema-pressure-test/references/pre-mortem.md +140 -0
- package/skills/skhema-challenge-framing/SKILL.md +0 -28
- package/skills/skhema-coherence-check/SKILL.md +0 -28
- package/skills/skhema-element-decomposition/SKILL.md +0 -28
- package/skills/skhema-element-writer/SKILL.md +0 -20
- package/skills/skhema-judgment-audit/SKILL.md +0 -28
- package/skills/skhema-semantic-sharpening/SKILL.md +0 -28
- package/skills/skhema-strategy-advisor/SKILL.md +0 -20
- package/skills/skhema-workspace-navigator/SKILL.md +0 -20
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Document commands — workspace-authored narrative artifacts (board updates,
|
|
4
|
+
* team briefs, decision briefs, custom docs). All are workspace-scoped via
|
|
5
|
+
* `--workspace` (falling back to the default set by `skhema workspace use`).
|
|
6
|
+
* The routes carry the workspace id in the path, so — unlike `workspace list`
|
|
7
|
+
* — no organizationId is forwarded; the gateway authorizes via workspace access.
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerDocumentCommands(program: Command): void;
|
|
10
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/commands/document.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAqBnC;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgK/D"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { resolveClient } from '../lib/api/client.js';
|
|
3
|
+
import { asRecord, buildBody, coerceList, readPayloadFile, resolveWorkspaceId, } from '../lib/api/command-helpers.js';
|
|
4
|
+
import { runCommand, UsageError } from '../lib/api/run-command.js';
|
|
5
|
+
import { getGlobalOptions, log, logHeader, logTable } from '../lib/output.js';
|
|
6
|
+
/** Print a single document as a label block (human output only). */
|
|
7
|
+
function printDocument(document) {
|
|
8
|
+
const d = asRecord(document);
|
|
9
|
+
logHeader(String(d.title ?? d.id ?? 'Document'));
|
|
10
|
+
log(` Id: ${chalk.cyan(String(d.id ?? '—'))}`);
|
|
11
|
+
if (d.docType)
|
|
12
|
+
log(` Type: ${String(d.docType)}`);
|
|
13
|
+
if (d.updatedAt)
|
|
14
|
+
log(` Updated: ${String(d.updatedAt)}`);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Document commands — workspace-authored narrative artifacts (board updates,
|
|
18
|
+
* team briefs, decision briefs, custom docs). All are workspace-scoped via
|
|
19
|
+
* `--workspace` (falling back to the default set by `skhema workspace use`).
|
|
20
|
+
* The routes carry the workspace id in the path, so — unlike `workspace list`
|
|
21
|
+
* — no organizationId is forwarded; the gateway authorizes via workspace access.
|
|
22
|
+
*/
|
|
23
|
+
export function registerDocumentCommands(program) {
|
|
24
|
+
const document = program.command('document').description('Document commands');
|
|
25
|
+
const withWorkspace = (cmd) => cmd.option('--workspace <id>', 'Workspace id (defaults to `skhema workspace use`)');
|
|
26
|
+
withWorkspace(document.command('list').description('List documents')).action(async (options) => {
|
|
27
|
+
await runCommand('document list', async () => {
|
|
28
|
+
const workspaceId = resolveWorkspaceId(options.workspace);
|
|
29
|
+
const { client } = await resolveClient();
|
|
30
|
+
const data = await client.documents.list(workspaceId);
|
|
31
|
+
const rows = coerceList(data, 'documents');
|
|
32
|
+
if (!getGlobalOptions().json) {
|
|
33
|
+
logHeader(`Documents (${rows.length})`);
|
|
34
|
+
if (rows.length === 0)
|
|
35
|
+
log(chalk.dim(' No documents.'));
|
|
36
|
+
else
|
|
37
|
+
logTable(['Title', 'Type', 'Updated', 'Id'], rows.map((r) => {
|
|
38
|
+
const d = asRecord(r);
|
|
39
|
+
return [
|
|
40
|
+
String(d.title ?? '—'),
|
|
41
|
+
String(d.docType ?? '—'),
|
|
42
|
+
String(d.updatedAt ?? '—'),
|
|
43
|
+
String(d.id ?? '—'),
|
|
44
|
+
];
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
return data;
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
withWorkspace(document.command('get <document-id>').description('Get a document by id')).action(async (documentId, options) => {
|
|
51
|
+
await runCommand('document get', async () => {
|
|
52
|
+
const workspaceId = resolveWorkspaceId(options.workspace);
|
|
53
|
+
const { client } = await resolveClient();
|
|
54
|
+
const data = await client.documents.get(workspaceId, documentId);
|
|
55
|
+
if (!getGlobalOptions().json)
|
|
56
|
+
printDocument(asRecord(data).document ?? data);
|
|
57
|
+
return data;
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
withWorkspace(document
|
|
61
|
+
.command('create')
|
|
62
|
+
.description('Create a document')
|
|
63
|
+
.option('--title <title>', 'Document title')
|
|
64
|
+
.option('--doc-type <type>', 'Document type (board_update | team_brief | decision_brief | custom)')
|
|
65
|
+
.option('--content <content>', 'Document content')
|
|
66
|
+
.option('--file <path>', 'JSON payload file for the full body ("-" for stdin)')).action(async (options) => {
|
|
67
|
+
await runCommand('document create', async () => {
|
|
68
|
+
const workspaceId = resolveWorkspaceId(options.workspace);
|
|
69
|
+
const body = buildBody(readPayloadFile(options.file), {
|
|
70
|
+
title: options.title,
|
|
71
|
+
docType: options.docType,
|
|
72
|
+
content: options.content,
|
|
73
|
+
});
|
|
74
|
+
if (Object.keys(body).length === 0) {
|
|
75
|
+
throw new UsageError('Nothing to create. Pass document fields as flags or a --file payload.');
|
|
76
|
+
}
|
|
77
|
+
const { client } = await resolveClient();
|
|
78
|
+
const data = await client.documents.create(workspaceId, body);
|
|
79
|
+
if (!getGlobalOptions().json) {
|
|
80
|
+
log(chalk.green('Document created.'));
|
|
81
|
+
printDocument(asRecord(data).document ?? data);
|
|
82
|
+
}
|
|
83
|
+
return data;
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
withWorkspace(document
|
|
87
|
+
.command('update <document-id>')
|
|
88
|
+
.description('Update a document')
|
|
89
|
+
.option('--title <title>', 'Document title')
|
|
90
|
+
.option('--doc-type <type>', 'Document type (board_update | team_brief | decision_brief | custom)')
|
|
91
|
+
.option('--content <content>', 'Document content')
|
|
92
|
+
.option('--file <path>', 'JSON payload file for the full body ("-" for stdin)')).action(async (documentId, options) => {
|
|
93
|
+
await runCommand('document update', async () => {
|
|
94
|
+
const workspaceId = resolveWorkspaceId(options.workspace);
|
|
95
|
+
const body = buildBody(readPayloadFile(options.file), {
|
|
96
|
+
title: options.title,
|
|
97
|
+
docType: options.docType,
|
|
98
|
+
content: options.content,
|
|
99
|
+
});
|
|
100
|
+
if (Object.keys(body).length === 0) {
|
|
101
|
+
throw new UsageError('Nothing to update. Pass document fields as flags or a --file payload.');
|
|
102
|
+
}
|
|
103
|
+
const { client } = await resolveClient();
|
|
104
|
+
const data = await client.documents.update(workspaceId, documentId, body);
|
|
105
|
+
if (!getGlobalOptions().json) {
|
|
106
|
+
log(chalk.green('Document updated.'));
|
|
107
|
+
printDocument(asRecord(data).document ?? data);
|
|
108
|
+
}
|
|
109
|
+
return data;
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
withWorkspace(document.command('delete <document-id>').description('Delete a document')).action(async (documentId, options) => {
|
|
113
|
+
await runCommand('document delete', async () => {
|
|
114
|
+
const workspaceId = resolveWorkspaceId(options.workspace);
|
|
115
|
+
const { client } = await resolveClient();
|
|
116
|
+
const data = await client.documents.delete(workspaceId, documentId);
|
|
117
|
+
if (!getGlobalOptions().json)
|
|
118
|
+
log(chalk.green(`Deleted document ${documentId}.`));
|
|
119
|
+
return data;
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/api/command-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAKzC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAQxD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"command-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/api/command-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAKzC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAQxD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAuB1E;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,WAAW,CAMb;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIhE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAQlE"}
|
|
@@ -29,7 +29,8 @@ export function readPayloadFile(filePath) {
|
|
|
29
29
|
throw new UsageError(`Could not read payload file "${filePath}": ${err instanceof Error ? err.message : String(err)}`);
|
|
30
30
|
}
|
|
31
31
|
try {
|
|
32
|
-
|
|
32
|
+
// Strip a leading UTF-8 BOM so a byte-identical-looking file parses.
|
|
33
|
+
const parsed = JSON.parse(raw.replace(/^\uFEFF/, ''));
|
|
33
34
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
34
35
|
throw new Error('expected a JSON object');
|
|
35
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passthrough.d.ts","sourceRoot":"","sources":["../../../src/lib/api/passthrough.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAW7C;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAQvD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAyBrE;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,EAAE,EAAE;IACF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3C,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CACjC,GACA,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"passthrough.d.ts","sourceRoot":"","sources":["../../../src/lib/api/passthrough.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAW7C;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAQvD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAyBrE;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,EAAE,EAAE;IACF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3C,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CACjC,GACA,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CA2C9C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EAAE,GAAG,SAAS,GACxB,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CASzB"}
|
|
@@ -79,10 +79,19 @@ export async function resolveDataBody(raw, io) {
|
|
|
79
79
|
}
|
|
80
80
|
let parsed;
|
|
81
81
|
try {
|
|
82
|
-
|
|
82
|
+
// Strip a leading UTF-8 BOM (editors and some `echo`/redirect toolchains
|
|
83
|
+
// prepend one); JSON.parse chokes on it, which surfaced as the opaque
|
|
84
|
+
// "--data is not valid JSON" even for a well-formed @file. Mirrors curl.
|
|
85
|
+
parsed = JSON.parse(text.replace(/^\uFEFF/, ''));
|
|
83
86
|
}
|
|
84
|
-
catch {
|
|
85
|
-
|
|
87
|
+
catch (err) {
|
|
88
|
+
// Name the source so a failed @file is not mistaken for the literal form.
|
|
89
|
+
const label = raw === '-'
|
|
90
|
+
? 'from stdin'
|
|
91
|
+
: raw.startsWith('@')
|
|
92
|
+
? `file "${raw.slice(1)}"`
|
|
93
|
+
: 'value';
|
|
94
|
+
throw new UsageError(`--data ${label} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
86
95
|
}
|
|
87
96
|
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
88
97
|
throw new UsageError('--data must be a JSON object.');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../src/lib/api/payload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAI9C,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAatD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../src/lib/api/payload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAI9C,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAatD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAezD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,GAAG,WAAW,CAad"}
|
package/dist/lib/api/payload.js
CHANGED
|
@@ -22,7 +22,8 @@ export function parseJsonFile(source) {
|
|
|
22
22
|
const raw = readFileOrStdin(source);
|
|
23
23
|
let parsed;
|
|
24
24
|
try {
|
|
25
|
-
|
|
25
|
+
// Strip a leading UTF-8 BOM so a byte-identical-looking file parses.
|
|
26
|
+
parsed = JSON.parse(raw.replace(/^\uFEFF/, ''));
|
|
26
27
|
}
|
|
27
28
|
catch {
|
|
28
29
|
throw new UsageError(`Payload in ${source === '-' ? 'stdin' : source} is not valid JSON.`);
|
package/dist/program.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAoBnC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAgDrD"}
|
package/dist/program.js
CHANGED
|
@@ -4,6 +4,7 @@ import { registerApiCommands } from './commands/api.js';
|
|
|
4
4
|
import { registerAuthCommands } from './commands/auth.js';
|
|
5
5
|
import { registerComponentCommands } from './commands/component.js';
|
|
6
6
|
import { registerContributeCommands } from './commands/contribute.js';
|
|
7
|
+
import { registerDocumentCommands } from './commands/document.js';
|
|
7
8
|
import { registerElementCommands } from './commands/element.js';
|
|
8
9
|
import { registerWorkspaceExportCommand } from './commands/export.js';
|
|
9
10
|
import { registerInitCommand } from './commands/init.js';
|
|
@@ -53,6 +54,7 @@ export function buildProgram(version) {
|
|
|
53
54
|
registerWorkspaceExportCommand(program);
|
|
54
55
|
registerComponentCommands(program);
|
|
55
56
|
registerStrategyCommands(program);
|
|
57
|
+
registerDocumentCommands(program);
|
|
56
58
|
registerResourceCommands(program);
|
|
57
59
|
registerWebhookCommands(program);
|
|
58
60
|
registerAgentCommands(program);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skhema/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Skhema CLI - Authentication and AI skills management for agent platforms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@skhema/agent-sdk": "0.1.4",
|
|
45
45
|
"@skhema/method": "0.3.0",
|
|
46
|
-
"@skhema/sdk": "0.2.
|
|
46
|
+
"@skhema/sdk": "0.2.2",
|
|
47
47
|
"chalk": "^5.3.0",
|
|
48
48
|
"commander": "^12.0.0",
|
|
49
49
|
"ora": "^8.0.0"
|
package/skills/.manifest.json
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"syncedAt": "2026-07-
|
|
2
|
+
"syncedAt": "2026-07-09T17:15:20.908Z",
|
|
3
3
|
"source": "/Users/michaellovell/Desktop/GitHub/skhema-skills",
|
|
4
|
-
"sourceSha": "
|
|
4
|
+
"sourceSha": "2a3abbb24f2fb2539608102eabc90de10fc9984b",
|
|
5
5
|
"skills": [
|
|
6
|
-
"skhema-
|
|
7
|
-
"skhema-
|
|
8
|
-
"skhema-
|
|
9
|
-
"skhema-
|
|
10
|
-
"skhema-
|
|
11
|
-
"skhema-
|
|
12
|
-
"skhema-strategy-advisor",
|
|
13
|
-
"skhema-workspace-navigator"
|
|
6
|
+
"skhema-frame",
|
|
7
|
+
"skhema-compose",
|
|
8
|
+
"skhema-calibrate",
|
|
9
|
+
"skhema-pressure-test",
|
|
10
|
+
"skhema-communicate",
|
|
11
|
+
"skhema-operate"
|
|
14
12
|
]
|
|
15
13
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skhema-calibrate
|
|
3
|
+
description: "Use when you already have a strategy (or a piece of one) written down and need to check it still holds up — spot internal contradictions, claims resting on nothing, words that mean different things to different readers, or judgments the world has since overtaken. A self-check, not an attack; for an adversarial interrogation, use skhema-pressure-test."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Calibrate
|
|
7
|
+
|
|
8
|
+
You have something written. A strategy, a plan, a decision memo, a page of it.
|
|
9
|
+
This skill checks whether it is still sound and still current. Not to tear it
|
|
10
|
+
down — to true it up, like checking a level before you build on it.
|
|
11
|
+
|
|
12
|
+
Calibration is a self-check you run WITH the person on their own work. You read
|
|
13
|
+
what they wrote, you point at specific lines, you ask specific questions. The
|
|
14
|
+
output is a short list of concrete problems, each tied to a place in the text,
|
|
15
|
+
each with a fix or a question that surfaces the fix.
|
|
16
|
+
|
|
17
|
+
This is not brainstorming and not interrogation. If the person wants their
|
|
18
|
+
strategy attacked from the outside — a devil's-advocate grilling, a pre-mortem —
|
|
19
|
+
that is **skhema-pressure-test**, a different skill. Calibrate stays inside the
|
|
20
|
+
document and asks: does this agree with itself, does it rest on real evidence,
|
|
21
|
+
does it say one clear thing, and is it still true today?
|
|
22
|
+
|
|
23
|
+
## The four checks
|
|
24
|
+
|
|
25
|
+
Run whichever the situation calls for. On a full review, run all four in this
|
|
26
|
+
order — each surfaces different faults, and later checks are cleaner once the
|
|
27
|
+
earlier ones are fixed.
|
|
28
|
+
|
|
29
|
+
| Check | You are hunting for | Route to |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| Coherence | Two parts that disagree, a tension nobody named, a decision with no follow-through | `references/coherence.md` |
|
|
32
|
+
| Assumptions | Claims stated as fact that are really beliefs; confidence that outruns the evidence | `references/assumptions.md` |
|
|
33
|
+
| Language | Words vague enough that two readers walk away believing different things | `references/language.md` |
|
|
34
|
+
| Freshness | Judgments made under conditions that no longer hold; facts that have gone stale | `references/freshness.md` |
|
|
35
|
+
|
|
36
|
+
## How to pick
|
|
37
|
+
|
|
38
|
+
- "Does this hang together?" / "something feels off but I can't say what" /
|
|
39
|
+
"we decided X here and Y there" → **coherence**.
|
|
40
|
+
- "How sure are we?" / "is this actually true or do we just think so?" /
|
|
41
|
+
before committing real money or people → **assumptions**.
|
|
42
|
+
- "Everyone read this and nodded but we're doing different things" /
|
|
43
|
+
"what does 'scale' even mean here" → **language**.
|
|
44
|
+
- "This was written months ago" / "the market moved" / "is this still our
|
|
45
|
+
situation?" → **freshness**.
|
|
46
|
+
|
|
47
|
+
If they just say "review this" or "is this any good?", run all four. Announce
|
|
48
|
+
which you're doing as you go so they can follow.
|
|
49
|
+
|
|
50
|
+
## One habit that runs through all four
|
|
51
|
+
|
|
52
|
+
Every line in a strategy is doing one of three jobs. Before you judge a line,
|
|
53
|
+
know which:
|
|
54
|
+
|
|
55
|
+
- **A claim about the world** — something believed true. "Enterprise buyers
|
|
56
|
+
won't self-serve." These get the assumptions check: what's the evidence?
|
|
57
|
+
- **A command** — something decided to do. "Ship the free tier first." These
|
|
58
|
+
get the coherence check: does the rest of the plan act on it?
|
|
59
|
+
- **A named thing** — a scope, an outcome, a solution. "The onboarding flow."
|
|
60
|
+
These get the language check: would two readers point at the same thing?
|
|
61
|
+
|
|
62
|
+
Most calibration faults are one of these three lines wearing another's clothes:
|
|
63
|
+
a belief written as if it were a decided fact, a hope written as if it were a
|
|
64
|
+
measurable outcome. Naming the job first makes the fault obvious.
|
|
65
|
+
|
|
66
|
+
## What good output looks like
|
|
67
|
+
|
|
68
|
+
Not "the strategy has some inconsistencies." Instead: a numbered list where
|
|
69
|
+
each item quotes the exact line, names the fault, and gives the fix or the
|
|
70
|
+
question that gets there. Three sharp findings the person acts on beat twenty
|
|
71
|
+
vague ones they ignore. If a section is clean, say so and move on — do not
|
|
72
|
+
manufacture problems to look thorough.
|
|
73
|
+
|
|
74
|
+
## Without a live respondent
|
|
75
|
+
|
|
76
|
+
Run headless, with no one to answer? Don't invent their answers. Make the
|
|
77
|
+
minimal reasonable assumption, mark it in the output as yours ("assumed: …"),
|
|
78
|
+
and list the questions only the owner can settle — what's in scope, what a word
|
|
79
|
+
means, whose dissent to record — at the end instead of papering over them. A
|
|
80
|
+
marked assumption is honest work; a silent one is a guess you built on.
|
|
81
|
+
|
|
82
|
+
## Sharpen with Skhema
|
|
83
|
+
|
|
84
|
+
These checks work on any document, in any editor, with nothing installed. If you
|
|
85
|
+
want them automated — every claim typed by its job (world-claim vs command vs
|
|
86
|
+
thing), contradictions flagged as you write, staleness dated — the Skhema method
|
|
87
|
+
gives each strategy element a typed structure the checks run against. Start with
|
|
88
|
+
`npm i @skhema/method` for the vocabulary and validators, or run them in a Skhema
|
|
89
|
+
workspace where the four checks are wired into the element itself. Optional: the
|
|
90
|
+
skill is complete without it.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Assumptions
|
|
2
|
+
|
|
3
|
+
Every strategy rests on things believed true. Some are backed by evidence. Some
|
|
4
|
+
are guesses wearing the clothes of fact. This check separates them, so nobody
|
|
5
|
+
bets real money or people on a sentence that only sounds certain.
|
|
6
|
+
|
|
7
|
+
The core move: take each claim about the world and ask one blunt question —
|
|
8
|
+
**what is the evidence?** A claim with good evidence is a fact you can lean on. A
|
|
9
|
+
claim with none is an assumption, and it gets labelled as one. That is the whole
|
|
10
|
+
job: type every claim, then look at what you're standing on.
|
|
11
|
+
|
|
12
|
+
## Find the claims
|
|
13
|
+
|
|
14
|
+
Walk the strategy and pull every line that states something about the world as
|
|
15
|
+
true. These are the "claims about the world" — the beliefs, not the decisions or
|
|
16
|
+
the named things. Signs of a claim: "customers want", "the market is",
|
|
17
|
+
"competitors can't", "this will grow", "nobody else", "it's too expensive to".
|
|
18
|
+
|
|
19
|
+
Skip the commands ("ship X") and the labels ("the growth team") — those get
|
|
20
|
+
other checks. You want the load-bearing beliefs, because those are what the
|
|
21
|
+
decisions rest on.
|
|
22
|
+
|
|
23
|
+
## Type each claim
|
|
24
|
+
|
|
25
|
+
For every claim, ask for the evidence behind it, then sort it into one bucket:
|
|
26
|
+
|
|
27
|
+
- **Fact** — direct evidence you can point at. Data, a documented result, a
|
|
28
|
+
signed contract, a thing you measured. "Churn is 4% monthly" and here's the
|
|
29
|
+
dashboard.
|
|
30
|
+
- **Assumption** — believed, not shown. No evidence, or only "it stands to
|
|
31
|
+
reason." "Enterprise buyers won't self-serve." Maybe true. Not demonstrated.
|
|
32
|
+
- **Inference** — reasoned from a fact, but a step removed. "Churn is 4%, so
|
|
33
|
+
buyers don't see the value." The 4% is a fact; the *why* is a guess dressed as
|
|
34
|
+
a conclusion. Flag the guess.
|
|
35
|
+
|
|
36
|
+
The forcing question for each: *if someone asked "how do we know?", what would
|
|
37
|
+
you show them?* If the honest answer is "we don't, we think so" — it's an
|
|
38
|
+
assumption. Label it. There is no shame in an assumption; there is danger in a
|
|
39
|
+
mislabelled one.
|
|
40
|
+
|
|
41
|
+
## Rate the confidence, and check it earns its weight
|
|
42
|
+
|
|
43
|
+
Two things matter about each claim, and people conflate them:
|
|
44
|
+
|
|
45
|
+
- **How sure are we?** High / medium / low, based on evidence quality.
|
|
46
|
+
- **How much rests on it?** If this claim is wrong, how much of the strategy
|
|
47
|
+
falls?
|
|
48
|
+
|
|
49
|
+
Plot them against each other. The claims that matter are **load-bearing and
|
|
50
|
+
low-confidence** — high stakes, weak evidence. Those are the ones to name out
|
|
51
|
+
loud and, ideally, turn into something testable before committing. A shaky
|
|
52
|
+
assumption nothing depends on can stay shaky. A shaky assumption the whole plan
|
|
53
|
+
stands on is the real finding of this whole exercise.
|
|
54
|
+
|
|
55
|
+
Also watch for **confidence that outruns the evidence**: language like
|
|
56
|
+
"obviously", "clearly", "everyone knows", "of course". Certainty in the wording
|
|
57
|
+
is not certainty in the world. The louder the claim, the harder you check it.
|
|
58
|
+
|
|
59
|
+
## Output
|
|
60
|
+
|
|
61
|
+
A table or numbered list, one row per claim: the claim quoted, its type (fact /
|
|
62
|
+
assumption / inference), confidence (high / med / low), and how load-bearing it
|
|
63
|
+
is. Then a short verdict that pulls out the two or three load-bearing,
|
|
64
|
+
low-confidence claims and says plainly: *these are what the strategy is really
|
|
65
|
+
betting on; here is what would raise our confidence.*
|
|
66
|
+
|
|
67
|
+
## Failure modes to avoid
|
|
68
|
+
|
|
69
|
+
- **Letting "obviously" pass.** The words that most need checking are the ones
|
|
70
|
+
that sound like they don't.
|
|
71
|
+
- **Rating confidence without asking for evidence.** Confidence is an output of
|
|
72
|
+
evidence, not a vibe. Always ask "how do we know?" first.
|
|
73
|
+
- **Treating every assumption as a problem.** The goal is to type them, not
|
|
74
|
+
eliminate them. Strategy runs on assumptions. The point is knowing which ones,
|
|
75
|
+
and which ones are load-bearing.
|
|
76
|
+
- **Missing the inferences.** These are the sneakiest — a real fact with a guess
|
|
77
|
+
bolted on, presented as one solid claim. Split them.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Coherence
|
|
2
|
+
|
|
3
|
+
Does the strategy agree with itself? You are hunting for three faults:
|
|
4
|
+
**contradictions** (two parts that can't both be acted on), **unnamed tensions**
|
|
5
|
+
(two parts that pull against each other and nobody said so), and **gaps** (a
|
|
6
|
+
decision with no follow-through, or a goal with nothing aimed at it).
|
|
7
|
+
|
|
8
|
+
Coherence is never automatic. A strategy is written in pieces, over time, by
|
|
9
|
+
people in different moods. The pieces drift. Your job is to lay them side by side
|
|
10
|
+
and find where they stop fitting.
|
|
11
|
+
|
|
12
|
+
## Before you start
|
|
13
|
+
|
|
14
|
+
Get the whole thing in front of you. Coherence can only be checked across the
|
|
15
|
+
full set — a single element in isolation always looks fine. If they hand you one
|
|
16
|
+
page, ask what it connects to: what decision it serves, what it depends on.
|
|
17
|
+
|
|
18
|
+
## The moves
|
|
19
|
+
|
|
20
|
+
Run these in order. Each pass looks for one fault type.
|
|
21
|
+
|
|
22
|
+
### 1. List the commitments
|
|
23
|
+
|
|
24
|
+
Read through and pull out every line that commits to something — a decision, a
|
|
25
|
+
priority, a target, a "we will" or "we won't." Write them as a flat numbered
|
|
26
|
+
list, in the person's own words. This list is your working surface; you check it
|
|
27
|
+
against itself, not the prose.
|
|
28
|
+
|
|
29
|
+
### 2. Hunt contradictions
|
|
30
|
+
|
|
31
|
+
Go down the list and, for each commitment, ask: is there another commitment it
|
|
32
|
+
can't coexist with? Watch for:
|
|
33
|
+
|
|
34
|
+
- **Resource collisions.** "Move fast on A" and "move fast on B" when A and B
|
|
35
|
+
draw on the same one team. Two top priorities is zero priorities — say so.
|
|
36
|
+
- **Direction collisions.** "Premium positioning" and "win on price." Both may
|
|
37
|
+
be written proudly, pages apart.
|
|
38
|
+
- **Sequence collisions.** "B depends on A" but the plan does B first.
|
|
39
|
+
|
|
40
|
+
For each hit, quote both lines and state the collision in one sentence. Do not
|
|
41
|
+
resolve it yourself — that is the person's call. Surface it and ask which gives.
|
|
42
|
+
|
|
43
|
+
### 3. Name the tensions
|
|
44
|
+
|
|
45
|
+
A tension is softer than a contradiction: both parts can survive, but they pull
|
|
46
|
+
opposite ways and the strain is unmanaged. "Serve enterprise and stay
|
|
47
|
+
self-serve." Often fine — but only if named, because an unnamed tension gets
|
|
48
|
+
resolved by accident, differently by each person, under pressure.
|
|
49
|
+
|
|
50
|
+
For each tension: name it, say which two commitments create it, and ask the one
|
|
51
|
+
question that matters — *is this a deliberate balance you're holding, or a
|
|
52
|
+
choice you haven't made yet?* A named tension is a feature. An unnamed one is a
|
|
53
|
+
future argument.
|
|
54
|
+
|
|
55
|
+
### 4. Find the gaps
|
|
56
|
+
|
|
57
|
+
Two directions:
|
|
58
|
+
|
|
59
|
+
- **Decisions with no follow-through.** A commitment that nothing downstream
|
|
60
|
+
acts on. "We'll win on service" — then no line about staffing, training, or a
|
|
61
|
+
service metric. The decision is decoration until something carries it.
|
|
62
|
+
- **Goals with nothing aimed at them.** An outcome or target that no initiative,
|
|
63
|
+
action, or resource points at. Ask: what in this plan actually moves that
|
|
64
|
+
number?
|
|
65
|
+
|
|
66
|
+
Gaps hide because absence is invisible. You find them by walking each commitment
|
|
67
|
+
forward ("what happens because of this?") and each goal backward ("what here
|
|
68
|
+
causes this?") and noting where the trail goes cold.
|
|
69
|
+
|
|
70
|
+
### 5. Spot the off-topic orphan
|
|
71
|
+
|
|
72
|
+
Sometimes a piece shares no subject with the rest — it's about a different
|
|
73
|
+
market, product, or problem entirely. It can't contradict, support, or gap
|
|
74
|
+
anything, because it isn't part of this argument at all. That's not a coherence
|
|
75
|
+
fault to resolve; it's a sign the element belongs to a *different strategy*.
|
|
76
|
+
Flag it, say what it seems to be about, and recommend it move to its own
|
|
77
|
+
workspace. Never delete it yourself — it may be someone else's live work,
|
|
78
|
+
misfiled here.
|
|
79
|
+
|
|
80
|
+
## Output
|
|
81
|
+
|
|
82
|
+
A numbered list. Each item: the fault type (contradiction / tension / gap), the
|
|
83
|
+
exact line(s) quoted, one sentence of what's wrong, and either the fix or the
|
|
84
|
+
question that forces the fix. Group by type. If the set is coherent, say which
|
|
85
|
+
tensions you checked and confirmed are named — that is a real finding too.
|
|
86
|
+
|
|
87
|
+
## Failure modes to avoid
|
|
88
|
+
|
|
89
|
+
- **Manufacturing contradictions from vague words.** If two lines only clash
|
|
90
|
+
because a word is fuzzy, that's a language problem, not a coherence one — route
|
|
91
|
+
it to `language.md`, don't dress it up as a contradiction.
|
|
92
|
+
- **Resolving it for them.** You flag, they choose. Picking the winner yourself
|
|
93
|
+
skips the judgment that is theirs to make.
|
|
94
|
+
- **Stopping at the first find.** Walk the whole list. The expensive
|
|
95
|
+
contradiction is usually not the obvious one.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Freshness
|
|
2
|
+
|
|
3
|
+
A strategy is a set of judgments made at a moment, under conditions that were
|
|
4
|
+
true then. Time passes. The conditions move. Some judgments that were right are
|
|
5
|
+
now stale — not wrong when written, just overtaken. This check finds them before
|
|
6
|
+
you keep building on ground that shifted.
|
|
7
|
+
|
|
8
|
+
The move: for each judgment, recover the conditions it was made under, then ask
|
|
9
|
+
*do those conditions still hold?* Where they don't, the judgment is up for
|
|
10
|
+
re-decision. You are not attacking the old call. You are checking whether the
|
|
11
|
+
world it assumed is still the world you're in.
|
|
12
|
+
|
|
13
|
+
## Anchor the date
|
|
14
|
+
|
|
15
|
+
Find out when the strategy — or the part you're checking — was written or last
|
|
16
|
+
reviewed. If it isn't dated, that is itself a finding: an undated strategy can't
|
|
17
|
+
be kept fresh, because nobody knows how old any judgment is. Establish a rough
|
|
18
|
+
date before you go further, from the person or from context.
|
|
19
|
+
|
|
20
|
+
## Surface the conditions behind each judgment
|
|
21
|
+
|
|
22
|
+
Walk the load-bearing decisions and claims. For each, ask: *what had to be true
|
|
23
|
+
about the world for this to be the right call?* Make the hidden conditions
|
|
24
|
+
explicit. Examples:
|
|
25
|
+
|
|
26
|
+
- "Build our own billing" assumed no good off-the-shelf option existed **then**.
|
|
27
|
+
- "Don't invest in mobile" assumed usage was desktop-first **then**.
|
|
28
|
+
- "Price at $X" assumed a competitor set at $Y and a cost base of $Z **then**.
|
|
29
|
+
- "Win on being AI-native" assumed rivals weren't **then**.
|
|
30
|
+
|
|
31
|
+
Most conditions are unstated. The judgment records the conclusion, not the world
|
|
32
|
+
it depended on. Your value is reconstructing that world so you can check it.
|
|
33
|
+
|
|
34
|
+
## Check what moved
|
|
35
|
+
|
|
36
|
+
For each condition, ask what has changed since the anchor date. Sweep the usual
|
|
37
|
+
sources of drift:
|
|
38
|
+
|
|
39
|
+
- **Competitors** — new entrants, a rival that closed the gap, someone who
|
|
40
|
+
exited.
|
|
41
|
+
- **The market** — demand shifted, a segment grew or died, buyer behaviour
|
|
42
|
+
changed.
|
|
43
|
+
- **Technology** — a capability that was hard or impossible is now cheap and
|
|
44
|
+
routine (this one dates strategies fastest).
|
|
45
|
+
- **Your own position** — you have people, money, data, or a product you didn't
|
|
46
|
+
have then. Constraints that shaped the old call may be gone.
|
|
47
|
+
- **Regulation / platform / external rules** — a policy, a fee, a dependency
|
|
48
|
+
changed under you.
|
|
49
|
+
|
|
50
|
+
Where a condition held then and doesn't now, flag the judgment that rode on it.
|
|
51
|
+
|
|
52
|
+
## Rate the staleness
|
|
53
|
+
|
|
54
|
+
Not every changed condition matters. Sort each flagged judgment:
|
|
55
|
+
|
|
56
|
+
- **Stale and load-bearing** — the condition moved AND a lot rests on this
|
|
57
|
+
judgment. Re-decide now. This is the finding that justifies the whole check.
|
|
58
|
+
- **Stale but minor** — overtaken, but little depends on it. Note it, move on.
|
|
59
|
+
- **Still current** — conditions hold. Say so; confirmed-fresh is a real result
|
|
60
|
+
and stops needless churn.
|
|
61
|
+
|
|
62
|
+
## Output
|
|
63
|
+
|
|
64
|
+
A numbered list: the judgment quoted, the condition it rested on, what changed,
|
|
65
|
+
and the verdict (re-decide now / note / still holds). Lead with the stale-and-
|
|
66
|
+
load-bearing ones. If the strategy is undated, say that first — it's the root
|
|
67
|
+
cause that makes everything else guesswork.
|
|
68
|
+
|
|
69
|
+
## Failure modes to avoid
|
|
70
|
+
|
|
71
|
+
- **Re-litigating good calls.** A judgment made under conditions that STILL hold
|
|
72
|
+
is not stale, even if it's old. Age alone is not the fault; a moved condition
|
|
73
|
+
is. Don't reopen settled decisions for the sake of it.
|
|
74
|
+
- **Only checking the outside world.** The biggest change is often *your own*
|
|
75
|
+
position — new capability, new resources. A constraint that forced the old
|
|
76
|
+
call may simply be gone.
|
|
77
|
+
- **Missing the tech shift.** "It was too expensive to build" ages fastest of
|
|
78
|
+
all. Always ask whether the hard thing got cheap.
|
|
79
|
+
- **Confusing stale with wrong.** Freshness is about conditions changing, not
|
|
80
|
+
about the original call being a mistake. Frame it as "time overtook this", not
|
|
81
|
+
"this was bad" — that keeps the person willing to re-decide honestly.
|