Skip to content

Commit 6397ff9

Browse files
committed
feat: generate kiro power in agent-context
1 parent 9048d8e commit 6397ff9

6 files changed

Lines changed: 158 additions & 10 deletions

File tree

.github/workflows/sync-agent-context.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,22 @@ jobs:
4444
repository: mintlify/codex-plugin
4545
repository_name: codex-plugin
4646
mcp_file: .mcp.json
47+
manifest_file: ""
4748
- target: cursor
4849
repository: mintlify/cursor-plugin
4950
repository_name: cursor-plugin
5051
mcp_file: mcp.json
52+
manifest_file: ""
5153
- target: claude
5254
repository: mintlify/mintlify-claude-plugin
5355
repository_name: mintlify-claude-plugin
5456
mcp_file: .mcp.json
57+
manifest_file: ""
58+
- target: kiro
59+
repository: mintlify/kiro-power
60+
repository_name: kiro-power
61+
mcp_file: mcp.json
62+
manifest_file: plugin.json
5563

5664
steps:
5765
- name: Check out context source
@@ -106,6 +114,9 @@ jobs:
106114
git config user.email "${APP_SLUG}[bot]@users.noreply.github.com"
107115
git checkout -B "$BRANCH"
108116
git add skills/mintlify .mintlify-agent-context.json "${{ matrix.mcp_file }}"
117+
if [[ -n "${{ matrix.manifest_file }}" ]]; then
118+
git add "${{ matrix.manifest_file }}"
119+
fi
109120
git commit -m "Sync Mintlify agent context"
110121
git fetch origin "$BRANCH:refs/remotes/origin/$BRANCH" || true
111122
git push --force-with-lease origin "HEAD:$BRANCH"

agent-context/README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
# Mintlify agent context
22

3-
Single source of truth, maintained in the Mintlify documentation repository, for the Mintlify skill distributed through the Codex, Cursor, and Claude plugins.
3+
Single source of truth, maintained in the Mintlify documentation repository, for the Mintlify skill distributed through the Codex, Cursor, and Claude plugins and the Kiro power.
44

55
## Repository structure
66

77
- `context/skills/mintlify/` contains canonical, client-neutral context.
88
- `context/mcp-servers.json` contains canonical MCP names, URLs, and transport settings.
9-
- `targets/*.json` contains only client packaging differences such as MCP config file and schema names.
9+
- `targets/*.json` contains only client packaging differences such as MCP config file and schema names. The Kiro target also contains its required Agent Plugins manifest.
1010
- `scripts/build.mjs` renders self-contained plugin artifacts into `dist/`.
1111
- `scripts/sync-target.mjs` replaces only `skills/mintlify/` in a target repository.
12-
- `../.github/workflows/sync-agent-context.yml` opens generated sync pull requests in all three plugin repositories.
12+
- `../.github/workflows/sync-agent-context.yml` opens generated sync pull requests in all four target repositories.
1313

14-
Plugin manifests, assets, READMEs, and Cursor rules remain owned by their target repositories. This project generates the shared skill and each client's MCP configuration file.
14+
Plugin manifests, assets, READMEs, and Cursor rules remain owned by their target repositories, except for Kiro's required `plugin.json`, which is generated from its target configuration. This project generates the shared skill and each client's MCP configuration file.
1515

1616
## Local development
1717

@@ -28,6 +28,7 @@ Build one target by passing its ID:
2828

2929
```bash
3030
node scripts/build.mjs codex
31+
node scripts/build.mjs kiro
3132
```
3233

3334
Preview a sync into a local checkout:
@@ -37,7 +38,7 @@ node scripts/sync-target.mjs codex ../../codex-plugin
3738
git -C ../../codex-plugin diff
3839
```
3940

40-
The sync command replaces `skills/mintlify/`, writes the client-specific MCP configuration file, and writes `.mintlify-agent-context.json` with the source commit. It does not change any other plugin files.
41+
The sync command replaces `skills/mintlify/`, writes the client-specific MCP configuration file, and writes `.mintlify-agent-context.json` with the source commit. For Kiro, it also writes the required `plugin.json`. It does not change any other plugin files.
4142

4243
`npm run status` compares locally checked-out sibling plugin repositories with fresh builds and reports whether each one is current. Pass a workspace root as the final argument if the repositories do not share this repository's parent directory.
4344

@@ -48,6 +49,7 @@ Create a GitHub App installed on these repositories:
4849
- `mintlify/codex-plugin`
4950
- `mintlify/cursor-plugin`
5051
- `mintlify/mintlify-claude-plugin`
52+
- `mintlify/kiro-power`
5153

5254
Grant the app repository **Contents: read and write** and **Pull requests: read and write** permissions. Add its client ID as the `CONTEXT_SYNC_APP_CLIENT_ID` Actions variable and its private key as the `CONTEXT_SYNC_APP_PRIVATE_KEY` Actions secret in the `mintlify/docs` repository.
5355

agent-context/scripts/check.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const outputRoot = await mkdtemp(path.join(tmpdir(), 'mintlify-agent-context-'))
88

99
try {
1010
const results = await buildAll({ outputRoot });
11-
assert.equal(results.length, 3);
11+
assert.equal(results.length, 4);
1212

1313
const sharedFiles = [
1414
'api-docs.md',

agent-context/scripts/lib.mjs

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,30 @@ export async function loadTargets(selectedIds = []) {
2525
typeof target.id !== 'string' ||
2626
typeof target.repository !== 'string' ||
2727
!['.mcp.json', 'mcp.json'].includes(target.mcpConfigFile) ||
28-
!['mcp_servers', 'mcpServers'].includes(target.mcpConfigKey)
28+
!['mcp_servers', 'mcpServers'].includes(target.mcpConfigKey) ||
29+
(target.mcpSchema !== undefined && typeof target.mcpSchema !== 'string') ||
30+
(target.mcpTypeOverrides !== undefined &&
31+
(target.mcpTypeOverrides === null ||
32+
typeof target.mcpTypeOverrides !== 'object' ||
33+
Object.values(target.mcpTypeOverrides).some((value) => typeof value !== 'string')))
2934
) {
3035
throw new Error(`Invalid target configuration: ${JSON.stringify(target)}`);
3136
}
37+
38+
if (target.pluginManifest !== undefined) {
39+
const manifest = target.pluginManifest;
40+
if (
41+
manifest?.$schema !== 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json' ||
42+
typeof manifest.name !== 'string' ||
43+
typeof manifest.version !== 'string' ||
44+
typeof manifest.description !== 'string' ||
45+
typeof manifest.author?.name !== 'string' ||
46+
!Array.isArray(manifest.keywords) ||
47+
manifest.keywords.length === 0
48+
) {
49+
throw new Error(`Invalid plugin manifest: ${JSON.stringify(manifest)}`);
50+
}
51+
}
3252
}
3353

3454
const ids = new Set(targets.map((target) => target.id));
@@ -104,13 +124,31 @@ export async function buildTarget(target, outputRoot) {
104124
recursive: true,
105125
});
106126

107-
const mcpServers = JSON.parse(await readFile(mcpServersPath, 'utf8'));
108-
const mcpConfig = { [target.mcpConfigKey]: mcpServers };
127+
const canonicalMcpServers = JSON.parse(await readFile(mcpServersPath, 'utf8'));
128+
const mcpServers = Object.fromEntries(
129+
Object.entries(canonicalMcpServers).map(([name, server]) => [
130+
name,
131+
target.mcpTypeOverrides?.[server.type] === undefined
132+
? server
133+
: { ...server, type: target.mcpTypeOverrides[server.type] },
134+
]),
135+
);
136+
const mcpConfig = {
137+
...(target.mcpSchema === undefined ? {} : { $schema: target.mcpSchema }),
138+
[target.mcpConfigKey]: mcpServers,
139+
};
109140
await writeFile(
110141
path.join(targetRoot, target.mcpConfigFile),
111142
`${JSON.stringify(mcpConfig, null, 2)}\n`,
112143
);
113144

145+
if (target.pluginManifest !== undefined) {
146+
await writeFile(
147+
path.join(targetRoot, 'plugin.json'),
148+
`${JSON.stringify(target.pluginManifest, null, 2)}\n`,
149+
);
150+
}
151+
114152
const provenance = {
115153
schemaVersion: 1,
116154
sourceRepository: 'mintlify/docs',
@@ -147,6 +185,9 @@ export async function copyTargetToRepository(targetId, destination, outputRoot)
147185
path.join(sourceRoot, target.mcpConfigFile),
148186
path.join(destination, target.mcpConfigFile),
149187
);
188+
if (target.pluginManifest !== undefined) {
189+
await cp(path.join(sourceRoot, 'plugin.json'), path.join(destination, 'plugin.json'));
190+
}
150191
await cp(
151192
path.join(sourceRoot, '.mintlify-agent-context.json'),
152193
path.join(destination, '.mintlify-agent-context.json'),

agent-context/targets/kiro.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"id": "kiro",
3+
"repository": "mintlify/kiro-power",
4+
"mcpConfigFile": "mcp.json",
5+
"mcpConfigKey": "mcpServers",
6+
"mcpSchema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
7+
"mcpTypeOverrides": {
8+
"http": "streamable-http"
9+
},
10+
"pluginManifest": {
11+
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
12+
"name": "mintlify",
13+
"version": "1.0.0",
14+
"description": "Create, maintain, and improve Mintlify documentation with product guidance and Mintlify tools.",
15+
"author": {
16+
"name": "Mintlify",
17+
"url": "https://mintlify.com"
18+
},
19+
"keywords": [
20+
"mintlify",
21+
"documentation",
22+
"docs.json",
23+
"api documentation",
24+
"technical writing",
25+
"mdx",
26+
"openapi"
27+
],
28+
"homepage": "https://mintlify.com/docs",
29+
"repository": "https://github.com/mintlify/kiro-power",
30+
"license": "MIT"
31+
}
32+
}

agent-context/test/build.test.mjs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ test('builds all client variants from one canonical skill', async () => {
2222
path.join(outputRoot, 'claude', 'skills', 'mintlify', 'SKILL.md'),
2323
'utf8',
2424
);
25+
const kiro = await readFile(
26+
path.join(outputRoot, 'kiro', 'skills', 'mintlify', 'SKILL.md'),
27+
'utf8',
28+
);
2529
const codexMcp = JSON.parse(
2630
await readFile(path.join(outputRoot, 'codex', '.mcp.json'), 'utf8'),
2731
);
@@ -31,10 +35,17 @@ test('builds all client variants from one canonical skill', async () => {
3135
const claudeMcp = JSON.parse(
3236
await readFile(path.join(outputRoot, 'claude', '.mcp.json'), 'utf8'),
3337
);
38+
const kiroMcp = JSON.parse(
39+
await readFile(path.join(outputRoot, 'kiro', 'mcp.json'), 'utf8'),
40+
);
41+
const kiroManifest = JSON.parse(
42+
await readFile(path.join(outputRoot, 'kiro', 'plugin.json'), 'utf8'),
43+
);
3444

3545
assert.equal(cursor, codex);
3646
assert.equal(claude, codex);
37-
for (const skill of [codex, cursor, claude]) {
47+
assert.equal(kiro, codex);
48+
for (const skill of [codex, cursor, claude, kiro]) {
3849
assert.match(skill, /Generated from mintlify\/docs\/agent-context/);
3950
assert.match(skill, /### Mintlify Search/);
4051
assert.match(skill, /### Mintlify Admin/);
@@ -44,6 +55,28 @@ test('builds all client variants from one canonical skill', async () => {
4455
}
4556
assert.deepEqual(codexMcp.mcp_servers, cursorMcp.mcpServers);
4657
assert.deepEqual(claudeMcp.mcpServers, cursorMcp.mcpServers);
58+
assert.deepEqual(
59+
Object.fromEntries(
60+
Object.entries(kiroMcp.mcpServers).map(([name, server]) => [
61+
name,
62+
{ ...server, type: 'http' },
63+
]),
64+
),
65+
cursorMcp.mcpServers,
66+
);
67+
assert.ok(
68+
Object.values(kiroMcp.mcpServers).every((server) => server.type === 'streamable-http'),
69+
);
70+
assert.equal(
71+
kiroMcp.$schema,
72+
'https://agent-plugins.org/schemas/1.0.0/mcp.schema.json',
73+
);
74+
assert.equal(
75+
kiroManifest.$schema,
76+
'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json',
77+
);
78+
assert.equal(kiroManifest.name, 'mintlify');
79+
assert.ok(kiroManifest.keywords.includes('mintlify'));
4780
assert.deepEqual(Object.keys(cursorMcp.mcpServers), [
4881
'Mintlify Search',
4982
'Mintlify Admin',
@@ -53,6 +86,35 @@ test('builds all client variants from one canonical skill', async () => {
5386
}
5487
});
5588

89+
test('sync writes the complete Kiro power without changing target-owned files', async () => {
90+
const root = await mkdtemp(path.join(tmpdir(), 'mintlify-agent-context-kiro-sync-test-'));
91+
const outputRoot = path.join(root, 'dist');
92+
const destination = path.join(root, 'kiro-power');
93+
94+
try {
95+
await mkdir(destination, { recursive: true });
96+
await writeFile(path.join(destination, 'README.md'), 'target-owned\n');
97+
98+
await buildAll({ outputRoot, selectedIds: ['kiro'] });
99+
await copyTargetToRepository('kiro', destination, outputRoot);
100+
101+
assert.equal(await readFile(path.join(destination, 'README.md'), 'utf8'), 'target-owned\n');
102+
const manifest = JSON.parse(await readFile(path.join(destination, 'plugin.json'), 'utf8'));
103+
const mcpConfig = JSON.parse(await readFile(path.join(destination, 'mcp.json'), 'utf8'));
104+
assert.equal(manifest.name, 'mintlify');
105+
assert.deepEqual(Object.keys(mcpConfig.mcpServers), [
106+
'Mintlify Search',
107+
'Mintlify Admin',
108+
]);
109+
assert.match(
110+
await readFile(path.join(destination, 'skills', 'mintlify', 'SKILL.md'), 'utf8'),
111+
/### Mintlify Search/,
112+
);
113+
} finally {
114+
await rm(root, { recursive: true, force: true });
115+
}
116+
});
117+
56118
test('sync replaces only generated context paths', async () => {
57119
const root = await mkdtemp(path.join(tmpdir(), 'mintlify-agent-context-sync-test-'));
58120
const outputRoot = path.join(root, 'dist');

0 commit comments

Comments
 (0)