@cubis/foundry 0.3.40 → 0.3.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -3
- package/bin/cubis.js +360 -26
- package/mcp/README.md +72 -8
- package/mcp/config.json +3 -0
- package/mcp/dist/index.js +315 -68
- package/mcp/src/config/index.test.ts +1 -0
- package/mcp/src/config/schema.ts +5 -0
- package/mcp/src/index.ts +40 -9
- package/mcp/src/server.ts +66 -10
- package/mcp/src/telemetry/tokenBudget.ts +114 -0
- package/mcp/src/tools/index.ts +7 -0
- package/mcp/src/tools/skillBrowseCategory.ts +22 -5
- package/mcp/src/tools/skillBudgetReport.ts +128 -0
- package/mcp/src/tools/skillGet.ts +18 -0
- package/mcp/src/tools/skillListCategories.ts +19 -6
- package/mcp/src/tools/skillSearch.ts +22 -5
- package/mcp/src/tools/skillTools.test.ts +61 -9
- package/mcp/src/vault/manifest.test.ts +19 -1
- package/mcp/src/vault/manifest.ts +12 -1
- package/mcp/src/vault/scanner.test.ts +1 -0
- package/mcp/src/vault/scanner.ts +1 -0
- package/mcp/src/vault/types.ts +6 -0
- package/package.json +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/rules/GEMINI.md +28 -0
- package/workflows/workflows/agent-environment-setup/platforms/codex/rules/AGENTS.md +31 -2
- package/workflows/workflows/agent-environment-setup/platforms/copilot/rules/AGENTS.md +28 -0
- package/workflows/workflows/agent-environment-setup/platforms/copilot/rules/copilot-instructions.md +28 -0
- package/workflows/workflows/agent-environment-setup/platforms/cursor/rules/.cursorrules +28 -0
- package/workflows/workflows/agent-environment-setup/platforms/windsurf/rules/.windsurfrules +28 -0
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import type { VaultManifest } from "../vault/types.js";
|
|
10
10
|
import { enrichWithDescriptions } from "../vault/manifest.js";
|
|
11
|
+
import {
|
|
12
|
+
buildSkillToolMetrics,
|
|
13
|
+
estimateTokensFromBytes,
|
|
14
|
+
estimateTokensFromText,
|
|
15
|
+
} from "../telemetry/tokenBudget.js";
|
|
11
16
|
|
|
12
17
|
export const skillSearchName = "skill_search";
|
|
13
18
|
|
|
@@ -27,6 +32,7 @@ export async function handleSkillSearch(
|
|
|
27
32
|
args: z.infer<typeof skillSearchSchema>,
|
|
28
33
|
manifest: VaultManifest,
|
|
29
34
|
summaryMaxLength: number,
|
|
35
|
+
charsPerToken: number,
|
|
30
36
|
) {
|
|
31
37
|
const { query } = args;
|
|
32
38
|
const lower = query.toLowerCase();
|
|
@@ -56,17 +62,28 @@ export async function handleSkillSearch(
|
|
|
56
62
|
category: s.category,
|
|
57
63
|
description: s.description ?? "(no description)",
|
|
58
64
|
}));
|
|
65
|
+
const payload = { query, results, count: results.length };
|
|
66
|
+
const text = JSON.stringify(payload, null, 2);
|
|
67
|
+
const selectedSkillsEstimatedTokens = matches.reduce(
|
|
68
|
+
(sum, skill) => sum + estimateTokensFromBytes(skill.fileBytes, charsPerToken),
|
|
69
|
+
0,
|
|
70
|
+
);
|
|
71
|
+
const metrics = buildSkillToolMetrics({
|
|
72
|
+
charsPerToken,
|
|
73
|
+
fullCatalogEstimatedTokens: manifest.fullCatalogEstimatedTokens,
|
|
74
|
+
responseEstimatedTokens: estimateTokensFromText(text, charsPerToken),
|
|
75
|
+
selectedSkillsEstimatedTokens,
|
|
76
|
+
});
|
|
59
77
|
|
|
60
78
|
return {
|
|
61
79
|
content: [
|
|
62
80
|
{
|
|
63
81
|
type: "text" as const,
|
|
64
|
-
text
|
|
65
|
-
{ query, results, count: results.length },
|
|
66
|
-
null,
|
|
67
|
-
2,
|
|
68
|
-
),
|
|
82
|
+
text,
|
|
69
83
|
},
|
|
70
84
|
],
|
|
85
|
+
structuredContent: {
|
|
86
|
+
metrics,
|
|
87
|
+
},
|
|
71
88
|
};
|
|
72
89
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { mkdtempSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import type { VaultManifest } from "../vault/types.js";
|
|
6
6
|
import { handleSkillBrowseCategory } from "./skillBrowseCategory.js";
|
|
7
|
+
import { handleSkillBudgetReport } from "./skillBudgetReport.js";
|
|
7
8
|
import { handleSkillGet } from "./skillGet.js";
|
|
8
9
|
import { handleSkillListCategories } from "./skillListCategories.js";
|
|
9
10
|
import { handleSkillSearch } from "./skillSearch.js";
|
|
@@ -12,6 +13,10 @@ function payload(result: { content: Array<{ text: string }> }): Record<string, u
|
|
|
12
13
|
return JSON.parse(result.content[0].text) as Record<string, unknown>;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
function metrics(result: { structuredContent?: Record<string, unknown> }): Record<string, unknown> {
|
|
17
|
+
return (result.structuredContent?.metrics || {}) as Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
function createSkillFile(id: string, description: string, body = "# Content"): string {
|
|
16
21
|
const dir = mkdtempSync(path.join(os.tmpdir(), `mcp-skill-${id}-`));
|
|
17
22
|
const file = path.join(dir, "SKILL.md");
|
|
@@ -32,27 +37,47 @@ function createManifest(): VaultManifest {
|
|
|
32
37
|
"fastapi-expert",
|
|
33
38
|
"FastAPI async backend patterns",
|
|
34
39
|
);
|
|
40
|
+
const reactBytes = statSync(reactFile).size;
|
|
41
|
+
const fastapiBytes = statSync(fastapiFile).size;
|
|
42
|
+
const fullCatalogBytes = reactBytes + fastapiBytes;
|
|
35
43
|
|
|
36
44
|
return {
|
|
37
45
|
categories: ["backend", "frontend"],
|
|
38
46
|
skills: [
|
|
39
|
-
{
|
|
40
|
-
|
|
47
|
+
{
|
|
48
|
+
id: "react-expert",
|
|
49
|
+
category: "frontend",
|
|
50
|
+
path: reactFile,
|
|
51
|
+
fileBytes: reactBytes,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "fastapi-expert",
|
|
55
|
+
category: "backend",
|
|
56
|
+
path: fastapiFile,
|
|
57
|
+
fileBytes: fastapiBytes,
|
|
58
|
+
},
|
|
41
59
|
],
|
|
60
|
+
fullCatalogBytes,
|
|
61
|
+
fullCatalogEstimatedTokens: Math.ceil(fullCatalogBytes / 4),
|
|
42
62
|
};
|
|
43
63
|
}
|
|
44
64
|
|
|
45
65
|
describe("skill tools", () => {
|
|
46
66
|
it("lists categories with skill counts", () => {
|
|
47
67
|
const manifest = createManifest();
|
|
48
|
-
const result = handleSkillListCategories(manifest);
|
|
68
|
+
const result = handleSkillListCategories(manifest, 4);
|
|
49
69
|
const data = payload(result);
|
|
70
|
+
const toolMetrics = metrics(result);
|
|
50
71
|
|
|
51
72
|
expect(data.totalSkills).toBe(2);
|
|
52
73
|
expect(data.categories).toEqual([
|
|
53
74
|
{ category: "backend", skillCount: 1 },
|
|
54
75
|
{ category: "frontend", skillCount: 1 },
|
|
55
76
|
]);
|
|
77
|
+
expect(toolMetrics.estimatorVersion).toBeDefined();
|
|
78
|
+
expect(toolMetrics.fullCatalogEstimatedTokens).toBe(
|
|
79
|
+
manifest.fullCatalogEstimatedTokens,
|
|
80
|
+
);
|
|
56
81
|
});
|
|
57
82
|
|
|
58
83
|
it("browses a category with enriched descriptions", async () => {
|
|
@@ -61,8 +86,10 @@ describe("skill tools", () => {
|
|
|
61
86
|
{ category: "frontend" },
|
|
62
87
|
manifest,
|
|
63
88
|
200,
|
|
89
|
+
4,
|
|
64
90
|
);
|
|
65
91
|
const data = payload(result);
|
|
92
|
+
const toolMetrics = metrics(result);
|
|
66
93
|
|
|
67
94
|
expect(data.category).toBe("frontend");
|
|
68
95
|
expect(data.count).toBe(1);
|
|
@@ -72,12 +99,13 @@ describe("skill tools", () => {
|
|
|
72
99
|
description: "React performance and architecture guidance",
|
|
73
100
|
},
|
|
74
101
|
]);
|
|
102
|
+
expect(toolMetrics.selectedSkillsEstimatedTokens).toBeGreaterThan(0);
|
|
75
103
|
});
|
|
76
104
|
|
|
77
105
|
it("throws when browsing an unknown category", async () => {
|
|
78
106
|
const manifest = createManifest();
|
|
79
107
|
await expect(
|
|
80
|
-
handleSkillBrowseCategory({ category: "mobile" }, manifest, 200),
|
|
108
|
+
handleSkillBrowseCategory({ category: "mobile" }, manifest, 200, 4),
|
|
81
109
|
).rejects.toThrow('Category not found: "mobile"');
|
|
82
110
|
});
|
|
83
111
|
|
|
@@ -85,7 +113,7 @@ describe("skill tools", () => {
|
|
|
85
113
|
const manifest = createManifest();
|
|
86
114
|
|
|
87
115
|
const byId = payload(
|
|
88
|
-
await handleSkillSearch({ query: "react" }, manifest, 200),
|
|
116
|
+
await handleSkillSearch({ query: "react" }, manifest, 200, 4),
|
|
89
117
|
);
|
|
90
118
|
expect(byId.count).toBe(1);
|
|
91
119
|
expect(byId.results).toEqual([
|
|
@@ -97,7 +125,7 @@ describe("skill tools", () => {
|
|
|
97
125
|
]);
|
|
98
126
|
|
|
99
127
|
const byDescription = payload(
|
|
100
|
-
await handleSkillSearch({ query: "async backend" }, manifest, 200),
|
|
128
|
+
await handleSkillSearch({ query: "async backend" }, manifest, 200, 4),
|
|
101
129
|
);
|
|
102
130
|
expect(byDescription.count).toBe(1);
|
|
103
131
|
expect(byDescription.results).toEqual([
|
|
@@ -111,16 +139,40 @@ describe("skill tools", () => {
|
|
|
111
139
|
|
|
112
140
|
it("returns full skill content for skill_get", async () => {
|
|
113
141
|
const manifest = createManifest();
|
|
114
|
-
const result = await handleSkillGet({ id: "react-expert" }, manifest);
|
|
142
|
+
const result = await handleSkillGet({ id: "react-expert" }, manifest, 4);
|
|
143
|
+
const toolMetrics = metrics(result);
|
|
115
144
|
|
|
116
145
|
expect(result.content[0].text).toContain("# Content");
|
|
117
146
|
expect(result.content[0].text).toContain("description: React performance");
|
|
147
|
+
expect(toolMetrics.loadedSkillEstimatedTokens).toBeGreaterThan(0);
|
|
118
148
|
});
|
|
119
149
|
|
|
120
150
|
it("throws when skill_get cannot find the requested skill", async () => {
|
|
121
151
|
const manifest = createManifest();
|
|
122
|
-
await expect(handleSkillGet({ id: "missing" }, manifest)).rejects.toThrow(
|
|
152
|
+
await expect(handleSkillGet({ id: "missing" }, manifest, 4)).rejects.toThrow(
|
|
123
153
|
'Skill not found: "missing"',
|
|
124
154
|
);
|
|
125
155
|
});
|
|
156
|
+
|
|
157
|
+
it("returns consolidated budget rollup for selected and loaded skills", () => {
|
|
158
|
+
const manifest = createManifest();
|
|
159
|
+
const result = handleSkillBudgetReport(
|
|
160
|
+
{
|
|
161
|
+
selectedSkillIds: ["react-expert", "missing-skill"],
|
|
162
|
+
loadedSkillIds: ["react-expert"],
|
|
163
|
+
},
|
|
164
|
+
manifest,
|
|
165
|
+
4,
|
|
166
|
+
);
|
|
167
|
+
const data = payload(result);
|
|
168
|
+
|
|
169
|
+
expect(data.skillLog).toBeDefined();
|
|
170
|
+
expect(data.contextBudget).toMatchObject({
|
|
171
|
+
fullCatalogEstimatedTokens: manifest.fullCatalogEstimatedTokens,
|
|
172
|
+
estimated: true,
|
|
173
|
+
});
|
|
174
|
+
expect(
|
|
175
|
+
(data.skillLog as Record<string, unknown>).unknownSelectedSkillIds,
|
|
176
|
+
).toContain("missing-skill");
|
|
177
|
+
});
|
|
126
178
|
});
|
|
@@ -3,6 +3,7 @@ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import {
|
|
6
|
+
buildManifest,
|
|
6
7
|
enrichWithDescriptions,
|
|
7
8
|
extractDescription,
|
|
8
9
|
parseDescriptionFromFrontmatter,
|
|
@@ -109,11 +110,12 @@ describe("manifest enrichment", () => {
|
|
|
109
110
|
|
|
110
111
|
const enriched = await enrichWithDescriptions(
|
|
111
112
|
[
|
|
112
|
-
{ id: "alpha", category: "general", path: fileA },
|
|
113
|
+
{ id: "alpha", category: "general", path: fileA, fileBytes: 64 },
|
|
113
114
|
{
|
|
114
115
|
id: "beta",
|
|
115
116
|
category: "general",
|
|
116
117
|
path: fileB,
|
|
118
|
+
fileBytes: 64,
|
|
117
119
|
description: "Already populated",
|
|
118
120
|
},
|
|
119
121
|
],
|
|
@@ -124,3 +126,19 @@ describe("manifest enrichment", () => {
|
|
|
124
126
|
expect(enriched[1].description).toBe("Already populated");
|
|
125
127
|
});
|
|
126
128
|
});
|
|
129
|
+
|
|
130
|
+
describe("buildManifest", () => {
|
|
131
|
+
it("computes full catalog byte and token totals", () => {
|
|
132
|
+
const manifest = buildManifest(
|
|
133
|
+
[
|
|
134
|
+
{ id: "a", category: "general", path: "/tmp/a.md", fileBytes: 20 },
|
|
135
|
+
{ id: "b", category: "frontend", path: "/tmp/b.md", fileBytes: 12 },
|
|
136
|
+
],
|
|
137
|
+
4,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
expect(manifest.categories).toEqual(["frontend", "general"]);
|
|
141
|
+
expect(manifest.fullCatalogBytes).toBe(32);
|
|
142
|
+
expect(manifest.fullCatalogEstimatedTokens).toBe(8);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -8,19 +8,30 @@
|
|
|
8
8
|
import { readFile } from "node:fs/promises";
|
|
9
9
|
import type { SkillPointer, VaultManifest } from "./types.js";
|
|
10
10
|
import { logger } from "../utils/logger.js";
|
|
11
|
+
import { estimateTokensFromBytes } from "../telemetry/tokenBudget.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Build a VaultManifest from scanned skill pointers.
|
|
14
15
|
* Categories are derived from the pointers.
|
|
15
16
|
*/
|
|
16
|
-
export function buildManifest(
|
|
17
|
+
export function buildManifest(
|
|
18
|
+
skills: SkillPointer[],
|
|
19
|
+
charsPerToken: number,
|
|
20
|
+
): VaultManifest {
|
|
17
21
|
const categorySet = new Set<string>();
|
|
22
|
+
let fullCatalogBytes = 0;
|
|
18
23
|
for (const skill of skills) {
|
|
19
24
|
categorySet.add(skill.category);
|
|
25
|
+
fullCatalogBytes += skill.fileBytes;
|
|
20
26
|
}
|
|
21
27
|
return {
|
|
22
28
|
categories: [...categorySet].sort(),
|
|
23
29
|
skills,
|
|
30
|
+
fullCatalogBytes,
|
|
31
|
+
fullCatalogEstimatedTokens: estimateTokensFromBytes(
|
|
32
|
+
fullCatalogBytes,
|
|
33
|
+
charsPerToken,
|
|
34
|
+
),
|
|
24
35
|
};
|
|
25
36
|
}
|
|
26
37
|
|
|
@@ -52,6 +52,7 @@ describe("scanVaultRoots", () => {
|
|
|
52
52
|
expect(byId["react-expert"]).toBe("frontend");
|
|
53
53
|
expect(byId["database-design"]).toBe("data");
|
|
54
54
|
expect(byId["custom-skill"]).toBe("general");
|
|
55
|
+
expect(skills.every((skill) => skill.fileBytes > 0)).toBe(true);
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
it("skips missing roots and continues scanning valid roots", async () => {
|
package/mcp/src/vault/scanner.ts
CHANGED
package/mcp/src/vault/types.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface SkillPointer {
|
|
|
9
9
|
category: string;
|
|
10
10
|
/** Absolute path to the SKILL.md file. */
|
|
11
11
|
path: string;
|
|
12
|
+
/** Skill file size in bytes. */
|
|
13
|
+
fileBytes: number;
|
|
12
14
|
/** Short description extracted from frontmatter (truncated). */
|
|
13
15
|
description?: string;
|
|
14
16
|
}
|
|
@@ -18,4 +20,8 @@ export interface VaultManifest {
|
|
|
18
20
|
categories: string[];
|
|
19
21
|
/** All skill pointers (metadata only – no full content). */
|
|
20
22
|
skills: SkillPointer[];
|
|
23
|
+
/** Total bytes across all discovered SKILL.md files. */
|
|
24
|
+
fullCatalogBytes: number;
|
|
25
|
+
/** Estimated full-catalog token usage (deterministic estimator). */
|
|
26
|
+
fullCatalogEstimatedTokens: number;
|
|
21
27
|
}
|
package/package.json
CHANGED
|
@@ -68,6 +68,32 @@ Use the best specialist first:
|
|
|
68
68
|
|
|
69
69
|
## 5) Skill Loading Policy
|
|
70
70
|
|
|
71
|
+
## MCP-first Skill Discovery Order (Required)
|
|
72
|
+
|
|
73
|
+
1. Use `skill_search` first to narrow candidate skills.
|
|
74
|
+
2. Use `skill_browse_category` second to inspect category-level candidates.
|
|
75
|
+
3. Use `skill_get` only for final selected skills that must be loaded.
|
|
76
|
+
4. Keep pointer-first flow; avoid loading full skill text prematurely.
|
|
77
|
+
|
|
78
|
+
## Skill Log Completion Block (Required)
|
|
79
|
+
|
|
80
|
+
After finishing skill selection/loading, publish:
|
|
81
|
+
|
|
82
|
+
- `selected_skills`: skill IDs selected for the task
|
|
83
|
+
- `loaded_skills`: skill IDs loaded via `skill_get`
|
|
84
|
+
- `skipped_skills`: considered but not loaded
|
|
85
|
+
|
|
86
|
+
## Context Budget Block (Required, Estimated)
|
|
87
|
+
|
|
88
|
+
Immediately after the Skill Log block, publish estimated budget fields:
|
|
89
|
+
|
|
90
|
+
- `full_catalog_est_tokens`
|
|
91
|
+
- `loaded_est_tokens`
|
|
92
|
+
- `estimated_savings_tokens`
|
|
93
|
+
- `estimated_savings_percent`
|
|
94
|
+
|
|
95
|
+
Mark all context/token values as deterministic estimates (not provider metering).
|
|
96
|
+
|
|
71
97
|
### Smart Skill Selection (Adaptive)
|
|
72
98
|
|
|
73
99
|
Use an adaptive load policy to control context size:
|
|
@@ -85,6 +111,8 @@ Use an adaptive load policy to control context size:
|
|
|
85
111
|
4. If a mapped skill is missing, continue with best fallback and state it.
|
|
86
112
|
5. Keep user-visible decision logs concise: selected skill(s) and one-line rationale.
|
|
87
113
|
|
|
114
|
+
After the skill log is complete, append the Context Budget block in the same response/update.
|
|
115
|
+
|
|
88
116
|
## 6) Socratic Gate (Before Complex Work)
|
|
89
117
|
|
|
90
118
|
Before multi-file or architecture-impacting changes, ask targeted questions when requirements are unclear:
|
|
@@ -14,12 +14,13 @@ This file defines mandatory behavior for Codex projects installed via `cbx workf
|
|
|
14
14
|
Before executing workflows, agents, or code edits, publish a short `Decision Log` that is visible to the user:
|
|
15
15
|
|
|
16
16
|
1. Rule file(s) read at startup (at minimum `AGENTS.md`, plus any additional rule files loaded).
|
|
17
|
-
2. Workflow decision (
|
|
18
|
-
3. Agent routing decision (
|
|
17
|
+
2. Workflow decision ($workflow-* or direct mode) and why it was chosen.
|
|
18
|
+
3. Agent routing decision ($agent-* or direct mode) and why it was chosen.
|
|
19
19
|
4. Skill loading decision (skill names loaded) and why they were chosen.
|
|
20
20
|
|
|
21
21
|
If routing changes during the task, publish a `Decision Update` before continuing.
|
|
22
22
|
Keep this user-visible summary concise and factual; do not expose private chain-of-thought.
|
|
23
|
+
When mentioning wrappers in user-visible logs, use raw $workflow-* and $agent-* tokens (no backticks) so Codex can render icon/blue mention styling.
|
|
23
24
|
|
|
24
25
|
## 2) Skill-Based Workflow
|
|
25
26
|
|
|
@@ -63,6 +64,32 @@ Use the best specialist first:
|
|
|
63
64
|
|
|
64
65
|
## 5) Skill Loading Policy
|
|
65
66
|
|
|
67
|
+
## MCP-first Skill Discovery Order (Required)
|
|
68
|
+
|
|
69
|
+
1. Use `skill_search` first to narrow candidate skills.
|
|
70
|
+
2. Use `skill_browse_category` second to inspect category-level candidates.
|
|
71
|
+
3. Use `skill_get` only for final selected skills that must be loaded.
|
|
72
|
+
4. Keep pointer-first flow; avoid loading full skill text prematurely.
|
|
73
|
+
|
|
74
|
+
## Skill Log Completion Block (Required)
|
|
75
|
+
|
|
76
|
+
After finishing skill selection/loading, publish:
|
|
77
|
+
|
|
78
|
+
- `selected_skills`: skill IDs selected for the task
|
|
79
|
+
- `loaded_skills`: skill IDs loaded via `skill_get`
|
|
80
|
+
- `skipped_skills`: considered but not loaded
|
|
81
|
+
|
|
82
|
+
## Context Budget Block (Required, Estimated)
|
|
83
|
+
|
|
84
|
+
Immediately after the Skill Log block, publish estimated budget fields:
|
|
85
|
+
|
|
86
|
+
- `full_catalog_est_tokens`
|
|
87
|
+
- `loaded_est_tokens`
|
|
88
|
+
- `estimated_savings_tokens`
|
|
89
|
+
- `estimated_savings_percent`
|
|
90
|
+
|
|
91
|
+
Mark all context/token values as deterministic estimates (not provider metering).
|
|
92
|
+
|
|
66
93
|
### Smart Skill Selection (Adaptive)
|
|
67
94
|
|
|
68
95
|
Use an adaptive load policy to control context size:
|
|
@@ -80,6 +107,8 @@ Use an adaptive load policy to control context size:
|
|
|
80
107
|
4. If a mapped skill is missing, continue with best fallback and state it.
|
|
81
108
|
5. Keep user-visible decision logs concise: selected skill(s) and one-line rationale.
|
|
82
109
|
|
|
110
|
+
After the skill log is complete, append the Context Budget block in the same response/update.
|
|
111
|
+
|
|
83
112
|
## 6) Socratic Gate (Before Complex Work)
|
|
84
113
|
|
|
85
114
|
Before multi-file or architecture-impacting changes, ask targeted questions when requirements are unclear:
|
|
@@ -72,6 +72,32 @@ When authoring custom Copilot assets, keep frontmatter schema compatible:
|
|
|
72
72
|
|
|
73
73
|
## 6) Skill Loading Policy
|
|
74
74
|
|
|
75
|
+
## MCP-first Skill Discovery Order (Required)
|
|
76
|
+
|
|
77
|
+
1. Use `skill_search` first to narrow candidate skills.
|
|
78
|
+
2. Use `skill_browse_category` second to inspect category-level candidates.
|
|
79
|
+
3. Use `skill_get` only for final selected skills that must be loaded.
|
|
80
|
+
4. Keep pointer-first flow; avoid loading full skill text prematurely.
|
|
81
|
+
|
|
82
|
+
## Skill Log Completion Block (Required)
|
|
83
|
+
|
|
84
|
+
After finishing skill selection/loading, publish:
|
|
85
|
+
|
|
86
|
+
- `selected_skills`: skill IDs selected for the task
|
|
87
|
+
- `loaded_skills`: skill IDs loaded via `skill_get`
|
|
88
|
+
- `skipped_skills`: considered but not loaded
|
|
89
|
+
|
|
90
|
+
## Context Budget Block (Required, Estimated)
|
|
91
|
+
|
|
92
|
+
Immediately after the Skill Log block, publish estimated budget fields:
|
|
93
|
+
|
|
94
|
+
- `full_catalog_est_tokens`
|
|
95
|
+
- `loaded_est_tokens`
|
|
96
|
+
- `estimated_savings_tokens`
|
|
97
|
+
- `estimated_savings_percent`
|
|
98
|
+
|
|
99
|
+
Mark all context/token values as deterministic estimates (not provider metering).
|
|
100
|
+
|
|
75
101
|
### Smart Skill Selection (Adaptive)
|
|
76
102
|
|
|
77
103
|
Use an adaptive load policy to control context size:
|
|
@@ -89,6 +115,8 @@ Use an adaptive load policy to control context size:
|
|
|
89
115
|
4. If a mapped skill is missing, continue with best fallback and state it.
|
|
90
116
|
5. Keep user-visible decision logs concise: selected skill(s) and one-line rationale.
|
|
91
117
|
|
|
118
|
+
After the skill log is complete, append the Context Budget block in the same response/update.
|
|
119
|
+
|
|
92
120
|
## 7) Socratic Gate (Before Complex Work)
|
|
93
121
|
|
|
94
122
|
Before multi-file or architecture-impacting changes, ask targeted questions when requirements are unclear:
|
package/workflows/workflows/agent-environment-setup/platforms/copilot/rules/copilot-instructions.md
CHANGED
|
@@ -72,6 +72,32 @@ When authoring custom Copilot assets, keep frontmatter schema compatible:
|
|
|
72
72
|
|
|
73
73
|
## 6) Skill Loading Policy
|
|
74
74
|
|
|
75
|
+
## MCP-first Skill Discovery Order (Required)
|
|
76
|
+
|
|
77
|
+
1. Use `skill_search` first to narrow candidate skills.
|
|
78
|
+
2. Use `skill_browse_category` second to inspect category-level candidates.
|
|
79
|
+
3. Use `skill_get` only for final selected skills that must be loaded.
|
|
80
|
+
4. Keep pointer-first flow; avoid loading full skill text prematurely.
|
|
81
|
+
|
|
82
|
+
## Skill Log Completion Block (Required)
|
|
83
|
+
|
|
84
|
+
After finishing skill selection/loading, publish:
|
|
85
|
+
|
|
86
|
+
- `selected_skills`: skill IDs selected for the task
|
|
87
|
+
- `loaded_skills`: skill IDs loaded via `skill_get`
|
|
88
|
+
- `skipped_skills`: considered but not loaded
|
|
89
|
+
|
|
90
|
+
## Context Budget Block (Required, Estimated)
|
|
91
|
+
|
|
92
|
+
Immediately after the Skill Log block, publish estimated budget fields:
|
|
93
|
+
|
|
94
|
+
- `full_catalog_est_tokens`
|
|
95
|
+
- `loaded_est_tokens`
|
|
96
|
+
- `estimated_savings_tokens`
|
|
97
|
+
- `estimated_savings_percent`
|
|
98
|
+
|
|
99
|
+
Mark all context/token values as deterministic estimates (not provider metering).
|
|
100
|
+
|
|
75
101
|
### Smart Skill Selection (TIER 0)
|
|
76
102
|
|
|
77
103
|
Before starting ANY task, the agent MUST:
|
|
@@ -88,6 +114,8 @@ Before starting ANY task, the agent MUST:
|
|
|
88
114
|
3. Keep context lean; avoid loading unrelated skill documents.
|
|
89
115
|
4. If a mapped skill is missing, continue with best fallback and state it.
|
|
90
116
|
|
|
117
|
+
After the skill log is complete, append the Context Budget block in the same response/update.
|
|
118
|
+
|
|
91
119
|
## 7) Socratic Gate (Before Complex Work)
|
|
92
120
|
|
|
93
121
|
Before multi-file or architecture-impacting changes, ask targeted questions when requirements are unclear:
|
|
@@ -32,11 +32,39 @@ Before starting ANY task, the agent MUST:
|
|
|
32
32
|
|
|
33
33
|
## 3) Skill Loading Policy
|
|
34
34
|
|
|
35
|
+
## MCP-first Skill Discovery Order (Required)
|
|
36
|
+
|
|
37
|
+
1. Use `skill_search` first to narrow candidate skills.
|
|
38
|
+
2. Use `skill_browse_category` second to inspect category-level candidates.
|
|
39
|
+
3. Use `skill_get` only for final selected skills that must be loaded.
|
|
40
|
+
4. Keep pointer-first flow; avoid loading full skill text prematurely.
|
|
41
|
+
|
|
42
|
+
## Skill Log Completion Block (Required)
|
|
43
|
+
|
|
44
|
+
After finishing skill selection/loading, publish:
|
|
45
|
+
|
|
46
|
+
- `selected_skills`: skill IDs selected for the task
|
|
47
|
+
- `loaded_skills`: skill IDs loaded via `skill_get`
|
|
48
|
+
- `skipped_skills`: considered but not loaded
|
|
49
|
+
|
|
50
|
+
## Context Budget Block (Required, Estimated)
|
|
51
|
+
|
|
52
|
+
Immediately after the Skill Log block, publish estimated budget fields:
|
|
53
|
+
|
|
54
|
+
- `full_catalog_est_tokens`
|
|
55
|
+
- `loaded_est_tokens`
|
|
56
|
+
- `estimated_savings_tokens`
|
|
57
|
+
- `estimated_savings_percent`
|
|
58
|
+
|
|
59
|
+
Mark all context/token values as deterministic estimates (not provider metering).
|
|
60
|
+
|
|
35
61
|
1. Load only skills needed for the active request.
|
|
36
62
|
2. Prefer progressive disclosure: start from `SKILL.md`, then specific sections.
|
|
37
63
|
3. Keep context lean; avoid loading unrelated skill documents.
|
|
38
64
|
4. If a mapped skill is missing, continue with best fallback and state it.
|
|
39
65
|
|
|
66
|
+
After the skill log is complete, append the Context Budget block in the same response/update.
|
|
67
|
+
|
|
40
68
|
## 4) Request Classifier
|
|
41
69
|
|
|
42
70
|
1. Question/explanation requests: answer directly.
|
|
@@ -32,11 +32,39 @@ Before starting ANY task, the agent MUST:
|
|
|
32
32
|
|
|
33
33
|
## 3) Skill Loading Policy
|
|
34
34
|
|
|
35
|
+
## MCP-first Skill Discovery Order (Required)
|
|
36
|
+
|
|
37
|
+
1. Use `skill_search` first to narrow candidate skills.
|
|
38
|
+
2. Use `skill_browse_category` second to inspect category-level candidates.
|
|
39
|
+
3. Use `skill_get` only for final selected skills that must be loaded.
|
|
40
|
+
4. Keep pointer-first flow; avoid loading full skill text prematurely.
|
|
41
|
+
|
|
42
|
+
## Skill Log Completion Block (Required)
|
|
43
|
+
|
|
44
|
+
After finishing skill selection/loading, publish:
|
|
45
|
+
|
|
46
|
+
- `selected_skills`: skill IDs selected for the task
|
|
47
|
+
- `loaded_skills`: skill IDs loaded via `skill_get`
|
|
48
|
+
- `skipped_skills`: considered but not loaded
|
|
49
|
+
|
|
50
|
+
## Context Budget Block (Required, Estimated)
|
|
51
|
+
|
|
52
|
+
Immediately after the Skill Log block, publish estimated budget fields:
|
|
53
|
+
|
|
54
|
+
- `full_catalog_est_tokens`
|
|
55
|
+
- `loaded_est_tokens`
|
|
56
|
+
- `estimated_savings_tokens`
|
|
57
|
+
- `estimated_savings_percent`
|
|
58
|
+
|
|
59
|
+
Mark all context/token values as deterministic estimates (not provider metering).
|
|
60
|
+
|
|
35
61
|
1. Load only skills needed for the active request.
|
|
36
62
|
2. Prefer progressive disclosure: start from `SKILL.md`, then specific sections.
|
|
37
63
|
3. Keep context lean; avoid loading unrelated skill documents.
|
|
38
64
|
4. If a mapped skill is missing, continue with best fallback and state it.
|
|
39
65
|
|
|
66
|
+
After the skill log is complete, append the Context Budget block in the same response/update.
|
|
67
|
+
|
|
40
68
|
## 4) Request Classifier
|
|
41
69
|
|
|
42
70
|
1. Question/explanation requests: answer directly.
|