Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/use/execute.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Import runtime APIs from **`kody:runtime`** when you need Kody helpers. These
helpers are runtime exports:

- use **`import { codemode } from 'kody:runtime'`** to call builtin capabilities
discovered by **search** as **`await codemode.capability_id(input)`** for
valid identifier names, or **`await codemode["capability-id"](input)`** for
non-identifier capability ids
- use
**`import { refreshAccessToken, createAuthenticatedFetch } from 'kody:runtime'`**
for integration OAuth helpers
Expand Down Expand Up @@ -94,6 +97,8 @@ user input, confirmation, or a result that changes the plan.
To read field shapes while coding, use **search** with
**`entity: "{name}:capability"`** for builtin capability type definitions, or
inspect the relevant saved package with **`entity: "{kody_id}:package"`**.
Capability detail includes a complete **execute** module snippet; the runtime
call itself is always through the imported `codemode` object.

## Saved packages

Expand Down
24 changes: 21 additions & 3 deletions docs/use/search.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ response must stay small.
## Single-entity detail

To get **full markdown and call shapes for one hit** (for example a capability’s
`inputTypeDefinition` / `outputTypeDefinition`), call **search** again with
**`entity`** set to `"{id}:{type}"` where **`type`** is `capability`, `value`,
`integration`, `package`, or `secret`.
ready-to-run **execute** snippet plus `inputTypeDefinition` /
`outputTypeDefinition`), call **search** again with **`entity`** set to
`"{id}:{type}"` where **`type`** is `capability`, `value`, `integration`,
`package`, or `secret`.

Examples:

Expand All @@ -46,6 +47,23 @@ Top-level ranked result cards include an explicit entity ref for each hit when
applicable, using that same `"{id}:{type}"` format, so you can immediately copy
the ref into a follow-up `entity` lookup when needed.

Capability detail shows the exact runtime pattern for **execute**:

```ts
import { codemode } from 'kody:runtime'

export default async function main(input = {}) {
return await codemode.kody_official_guide(input)
}
```

Use the capability id returned by **search** as the `codemode` method name, and
pass an object matching the displayed input type. Valid JavaScript identifier
ids use dot notation such as `codemode.kody_official_guide(input)`. If a
capability id is not a valid JavaScript identifier, use bracket notation such as
`codemode["capability-id"](input)`. Capability detail emits the exact form to
copy. Use `{}` when the capability has no required fields.

## When results look thin

If ranked search misses what you need, **rephrase the query** or use
Expand Down
4 changes: 2 additions & 2 deletions packages/worker/src/mcp/server-instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ What shows up in \`search\` (before you search)

search
- \`query\`: natural language; results are ranked (order matters). Optional \`limit\`, \`maxResponseSize\`.
- \`entity: "{id}:{type}"\` (\`capability\` | \`package\` | \`value\` | \`integration\` | \`secret\`) for one entity’s detail (TypeScript call shapes, usage). If a \`query\` returns no useful hits, rephrase or call \`meta_list_capabilities\` — \`entity\` does not repair an empty ranked list.
- \`entity: "{id}:{type}"\` (\`capability\` | \`package\` | \`value\` | \`integration\` | \`secret\`) for one entity’s detail. Capability detail includes an exact execute snippet and TypeScript call shapes; other entity details include usage. If a \`query\` returns no useful hits, rephrase or call \`meta_list_capabilities\` — \`entity\` does not repair an empty ranked list.
- Examples:
- search({ query: 'saved package for github automation' })
- search({ query: 'Cloudflare API zones dns workers d1' })
- search({ entity: 'kody_official_guide:capability' })

execute
- Single ESM module string with a default export such as \`export default async function main(input = {}) { ... }\`; \`params\` are passed as the first argument. Import runtime APIs from \`kody:runtime\`. Example: \`import { codemode, refreshAccessToken, createAuthenticatedFetch, workflows } from 'kody:runtime'\`. \`workflows.create\` can queue either inline \`code\` or a saved-package \`exportName\` through the shared Workflow hub. Prefer one \`execute\` when the plan is clear. Full rules for \`fetch\`, placeholders, \`secret_list\` / \`value_get\`, and \`x-kody-secret\`: see the \`execute\` tool description.
- Single ESM module string with a default export such as \`export default async function main(input = {}) { ... }\`; \`params\` are passed as the first argument. Import runtime APIs from \`kody:runtime\`. Example: \`import { codemode, refreshAccessToken, createAuthenticatedFetch, workflows } from 'kody:runtime'\`. Built-in capabilities returned by \`search\` are available through \`codemode\`: use \`await codemode.capability_id(input)\` for valid identifier names or \`await codemode["capability-id"](input)\` for non-identifier ids. \`workflows.create\` can queue either inline \`code\` or a saved-package \`exportName\` through the shared Workflow hub. Prefer one \`execute\` when the plan is clear. Full rules for \`fetch\`, placeholders, \`secret_list\` / \`value_get\`, and \`x-kody-secret\`: see the \`execute\` tool description.
- Cross-package imports use specifiers such as \`kody:@scope/my-package/export-name\`. For dynamic current-version calls inside package runtime code, prefer \`packages.invokeChecked({ kodyId, exportName, params })\` or \`packages.check(...)\` followed by \`packages.invoke(check.invoke)\`; use static imports for library-like bundled snapshots. Saved package names must be scoped (\`@scope/<leaf>\`) and the leaf segment must match \`kody.id\`. Package jobs are owned by packages, ad hoc jobs can be scheduled with \`job_schedule\`, and package apps are optional package surfaces.
- Official how-to guides from the Kody repo: if a requested package or workflow depends on a third-party integration, secrets, or OAuth, call \`kody_official_guide\` with \`guide: "integration_bootstrap"\` before building the package. Then load the relevant setup guide: \`oauth\` for standard third-party OAuth (\`/connect/oauth\`), \`connect_secret\` for secret collection, and \`secret_backed_integration\` for the default non-OAuth secret-backed recipe after bootstrap. If unsure, \`search\` for this capability and load the right guide before implementing.
- Do not save or present an auth-dependent package as complete until \`search\` shows the required integration or secret reference exists and a minimal authenticated \`execute\` smoke test succeeds.
Expand Down
4 changes: 2 additions & 2 deletions packages/worker/src/mcp/tools/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const executeTool = {
name: 'execute',
title: 'Execute Capabilities',
description: `
Run one ephemeral ESM module string with a default export. Imports may be arbitrary npm packages compatible with the Cloudflare Workers runtime (e.g. \`p-retry\`, \`mailparser\`, \`remark\`); prefer existing packages over rewriting helpers. Discover capability names with \`search\`; for one capability’s TypeScript call shape, call \`search\` with \`entity: "{name}:capability"\` or use \`meta_list_capabilities\`.
Run one ephemeral ESM module string with a default export. Imports may be arbitrary npm packages compatible with the Cloudflare Workers runtime (e.g. \`p-retry\`, \`mailparser\`, \`remark\`); prefer existing packages over rewriting helpers. Discover capability names with \`search\`; for one capability’s executable snippet and TypeScript call shape, call \`search\` with \`entity: "{name}:capability"\` or use \`meta_list_capabilities\`.

Projection rule: you write the code -- if a call returns a large response, project the fields you need before returning. Never return raw API responses; extract a slim shape (e.g. \`{ id, subject, snippet }\`) or a summary.

Expand All @@ -47,7 +47,7 @@ Saved package surface:

Sandbox surface:
- Import runtime helpers from \`kody:runtime\`.
- \`import { codemode } from 'kody:runtime'\` for builtin capabilities.
- \`import { codemode } from 'kody:runtime'\` for builtin capabilities discovered by \`search\`; call valid identifier names as \`await codemode.capability_id(input)\`. If a capability id is not a valid JavaScript identifier, use bracket notation: \`await codemode["capability-id"](input)\`. Capability detail from \`search({ entity: "{name}:capability" })\` includes the exact snippet.
- \`import { storage } from 'kody:runtime'\` for durable storage helpers on the bound \`storageId\`, including \`storage.sql(query, params?)\`. \`storage.sql\` returns \`{ columns, rows, rowCount, rowsRead, rowsWritten }\`; read query rows from \`.rows\`.
- \`import { refreshAccessToken, createAuthenticatedFetch } from 'kody:runtime'\` for OAuth integrations. Integration \`name\` may be account-specific (e.g. \`google-personal\`, \`google-business\`); call \`integration_list\` first when the task involves a provider that may have multiple accounts connected.
- \`import { workflows } from 'kody:runtime'\` for durable Cloudflare Workflows. \`workflows.create\` accepts either inline \`code\` or a saved-package \`exportName\`; use \`workflow_list\` to inspect recent runs.
Expand Down
59 changes: 59 additions & 0 deletions packages/worker/src/mcp/tools/search-format.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,69 @@ test('capability entity detail keeps type definitions stable without schema fiel

expect(detail.structured).toMatchObject({
type: 'capability',
usage: 'execute with codemode.github_create_issue(args)',
executeExample: expect.stringContaining(
'return await codemode.github_create_issue(input)',
),
inputTypeDefinition: expect.any(String),
outputTypeDefinition: expect.any(String),
})
expect(detail.markdown).toContain('## Execute from `execute`')
expect(detail.markdown).toContain("import { codemode } from 'kody:runtime'")
expect(detail.markdown).toContain(
'return await codemode.github_create_issue(input)',
)
expect(detail.structured).not.toHaveProperty('inputSchema')
expect(detail.structured).not.toHaveProperty('outputSchema')
})

test('capability usage uses bracket notation for non-identifier ids', () => {
const [match] = toSlimStructuredMatches({
baseUrl: 'http://localhost',
matches: [
{
type: 'capability',
name: 'foo-bar',
description: 'Capability with a non-identifier id.',
},
],
})
expect(match).toMatchObject({
type: 'capability',
usage: 'execute with codemode["foo-bar"](args)',
})

const detail = formatEntityDetailMarkdown({
type: 'capability',
id: 'foo-bar',
title: 'foo-bar',
description: 'Capability with a non-identifier id.',
spec: {
name: 'foo-bar',
domain: 'meta',
description: 'Capability with a non-identifier id.',
keywords: [],
readOnly: true,
idempotent: true,
destructive: false,
inputFields: [],
requiredInputFields: [],
outputFields: [],
inputSchema: { type: 'object', properties: {} },
inputTypeDefinition: 'type FooBarInput = Record<string, never>',
},
})

expect(detail.structured).toMatchObject({
type: 'capability',
usage: 'execute with codemode["foo-bar"](args)',
executeExample: expect.stringContaining(
'return await codemode["foo-bar"](input)',
),
})
expect(detail.markdown).toContain('return await codemode["foo-bar"](input)')
})

test('repo_run_commands capability detail keeps the structured capability contract', () => {
const registry = buildCapabilityRegistry(builtinDomains)
const repoRunCommands = registry.capabilitySpecs.repo_run_commands
Expand All @@ -247,6 +303,9 @@ test('repo_run_commands capability detail keeps the structured capability contra
title: 'repo_run_commands',
description: repoRunCommands.description,
usage: 'execute with codemode.repo_run_commands(args)',
executeExample: expect.stringContaining(
'return await codemode.repo_run_commands(input)',
),
requiredInputFields: ['commands'],
readOnly: expect.any(Boolean),
idempotent: expect.any(Boolean),
Expand Down
29 changes: 28 additions & 1 deletion packages/worker/src/mcp/tools/search-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export type SearchEntityDetailStructured =
title: string
description: string
usage: string
executeExample: string
requiredInputFields: Array<string>
readOnly: boolean
idempotent: boolean
Expand Down Expand Up @@ -413,7 +414,22 @@ function buildEntityRef(id: string, type: SearchEntityType) {
}

function buildCapabilityUsage(name: string) {
return `execute with codemode.${name}(args)`
return `execute with ${buildCodemodeCapabilityAccessor(name)}(args)`
}

function buildCodemodeCapabilityAccessor(name: string) {
if (/^[A-Za-z_$][\w$]*$/.test(name)) {
return `codemode.${name}`
}
return `codemode[${JSON.stringify(name)}]`
}

function buildCapabilityExecuteExample(name: string) {
return `import { codemode } from 'kody:runtime'

export default async function main(input = {}) {
\treturn await ${buildCodemodeCapabilityAccessor(name)}(input)
}`
Comment thread
cursor[bot] marked this conversation as resolved.
Resolved
}

function buildPackageRootImportUsage(packageName: string) {
Expand Down Expand Up @@ -756,6 +772,16 @@ export function formatEntityDetailMarkdown(detail: SearchEntityDetail) {
`- Idempotent: ${detail.spec.idempotent ? 'yes' : 'no'}`,
`- Destructive: ${detail.spec.destructive ? 'yes' : 'no'}`,
'',
'## Execute from `execute`',
'',
'Built-in capabilities returned by `search` are available inside `execute` as methods on the imported `codemode` object.',
'',
'```ts',
buildCapabilityExecuteExample(detail.spec.name),
'```',
'',
'Pass concrete arguments that satisfy the input type below; use `{}` when there are no required fields.',
'',
'## Type definitions',
'',
'```ts',
Expand All @@ -775,6 +801,7 @@ export function formatEntityDetailMarkdown(detail: SearchEntityDetail) {
title: detail.title,
description: detail.description,
usage: buildCapabilityUsage(detail.spec.name),
executeExample: buildCapabilityExecuteExample(detail.spec.name),
requiredInputFields: detail.spec.requiredInputFields,
readOnly: detail.spec.readOnly,
idempotent: detail.spec.idempotent,
Expand Down
5 changes: 3 additions & 2 deletions packages/worker/src/mcp/tools/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1416,8 +1416,9 @@ If nothing useful returns, rephrase or call \`meta_list_capabilities\`; \`entity
does not fix an empty ranked list.

**entity: "{id}:{type}"** — detail for one hit (\`capability\` | \`value\`
| \`integration\` | \`package\` | \`secret\`). Capability detail includes
TypeScript call-shape definitions by default.
| \`integration\` | \`package\` | \`secret\`). Capability detail includes an
exact \`execute\` module snippet plus TypeScript call-shape definitions by
default.

Packages: \`package_list\`, \`package_get\`, and \`repo_*\` for editing/publishing.
Open package apps with \`open_generated_ui({ kody_id })\` or use hosted package URLs.
Expand Down
Loading