@knightcodeai/cli 0.17.3 → 0.18.0
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/CHANGELOG.md +1293 -0
- package/README.md +2 -2
- package/dist/bundle/chunks/anthropic-messages-A2IH2IY3.js +6 -0
- package/dist/bundle/chunks/anthropic.js +101 -0
- package/dist/bundle/chunks/azure-openai-responses-XZILQZOG.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +89 -0
- package/dist/bundle/chunks/chunk-4CRI7BMY.js +2 -0
- package/dist/bundle/chunks/chunk-57BPR4HF.js +2 -0
- package/dist/bundle/chunks/chunk-A5LJINMT.js +2 -0
- package/dist/bundle/chunks/chunk-AANBXVWQ.js +2 -0
- package/dist/bundle/chunks/chunk-ACHHEROF.js +7 -0
- package/dist/bundle/chunks/chunk-AFR2OW6S.js +108 -0
- package/dist/bundle/chunks/chunk-AHB7JV5B.js +2 -0
- package/dist/bundle/chunks/chunk-B2FT7RH5.js +2 -0
- package/dist/bundle/chunks/chunk-BRKUE2MD.js +2 -0
- package/dist/bundle/chunks/chunk-DKOURXGU.js +2 -0
- package/dist/bundle/chunks/chunk-DVFCXHT4.js +2 -0
- package/dist/bundle/chunks/chunk-EPYT326Y.js +30 -0
- package/dist/bundle/chunks/chunk-ETOMYYZC.js +2 -0
- package/dist/bundle/chunks/chunk-FA32X2UJ.js +7 -0
- package/dist/bundle/chunks/chunk-FHM6KUY3.js +44 -0
- package/dist/bundle/chunks/chunk-FO7CEQB3.js +11 -0
- package/dist/bundle/chunks/chunk-GHVXUCGU.js +130 -0
- package/dist/bundle/chunks/chunk-HHWP56PR.js +2 -0
- package/dist/bundle/chunks/chunk-HSL72VZI.js +2 -0
- package/dist/bundle/chunks/chunk-HUQB436V.js +2 -0
- package/dist/bundle/chunks/chunk-HWXGL4YB.js +2 -0
- package/dist/bundle/chunks/chunk-KQKUEQJA.js +6 -0
- package/dist/bundle/chunks/chunk-M5GCRGV6.js +1333 -0
- package/dist/bundle/chunks/chunk-MB4QRS7Y.js +9 -0
- package/dist/bundle/chunks/chunk-MXIWLMNT.js +8 -0
- package/dist/bundle/chunks/chunk-N6VDWLND.js +2 -0
- package/dist/bundle/chunks/chunk-NCIBB66G.js +2 -0
- package/dist/bundle/chunks/chunk-NDQ5OW6U.js +2 -0
- package/dist/bundle/chunks/chunk-NNCIIYD6.js +2 -0
- package/dist/bundle/chunks/chunk-O6JSP6YG.js +6 -0
- package/dist/bundle/chunks/chunk-OFST7FDG.js +2 -0
- package/dist/bundle/chunks/chunk-SPAUY3RD.js +12 -0
- package/dist/bundle/chunks/chunk-U5XE4RWR.js +2 -0
- package/dist/bundle/chunks/chunk-UZWP3NHW.js +2 -0
- package/dist/bundle/chunks/chunk-V5ANFNKF.js +11 -0
- package/dist/bundle/chunks/chunk-VJJ6J35N.js +20 -0
- package/dist/bundle/chunks/chunk-XIRAUXOE.js +58 -0
- package/dist/bundle/chunks/chunk-ZW7FVRHT.js +31 -0
- package/dist/bundle/chunks/cli-6ZTWO6GL.js +51 -0
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-6E2UM7IG.js +2 -0
- package/dist/bundle/chunks/codemode-worker.js +478 -0
- package/dist/bundle/chunks/dist-DKI7Q6GY.js +13 -0
- package/dist/bundle/chunks/easter-egg-3d-FDCGDUF3.js +2 -0
- package/dist/bundle/chunks/execute-VSDU5VSN.js +499 -0
- package/dist/bundle/chunks/github-copilot.js +2 -0
- package/dist/bundle/chunks/google-generative-ai-CSWR3ORZ.js +2 -0
- package/dist/bundle/chunks/google-vertex-QIDRFOFB.js +2 -0
- package/dist/bundle/chunks/image-resize-worker.js +2 -0
- package/dist/bundle/chunks/jiti-loader-BXVX3Y2R.js +21 -0
- package/dist/bundle/chunks/jiti-static-loader-NNBCFAO5.js +2 -0
- package/dist/bundle/chunks/kimi-coding.js +2 -0
- package/dist/bundle/chunks/knightcode-messages-3GNOTMSI.js +8 -0
- package/dist/bundle/chunks/lib-IHWMWJDR.js +9 -0
- package/dist/bundle/chunks/llama-cpp-classify-HRPRKOZA.js +22 -0
- package/dist/bundle/chunks/meta.js +2 -0
- package/dist/bundle/chunks/mistral-conversations-46TK5OBA.js +5 -0
- package/dist/bundle/chunks/multipart-parser-VTTMF2EO.js +3 -0
- package/dist/bundle/chunks/node-7S3GFMOZ.js +16 -0
- package/dist/bundle/chunks/node-MAEICQNS.js +2 -0
- package/dist/bundle/chunks/openai-chatgpt.js +101 -0
- package/dist/bundle/chunks/openai-codex-responses-IT7VEKUU.js +10 -0
- package/dist/bundle/chunks/openai-codex.js +101 -0
- package/dist/bundle/chunks/openai-completions-LOKIW33V.js +7 -0
- package/dist/bundle/chunks/openai-decisions-4F3LWHMG.js +5 -0
- package/dist/bundle/chunks/openai-responses-OK36GJXP.js +3 -0
- package/dist/bundle/chunks/openrouter-images-ZI7LLZ4Y.js +2 -0
- package/dist/bundle/chunks/openrouter.js +101 -0
- package/dist/bundle/chunks/radius.js +101 -0
- package/dist/bundle/chunks/runtime-RMPIV5AR.js +2 -0
- package/dist/bundle/chunks/src-ETRMT73D.js +4 -0
- package/dist/bundle/chunks/typesafe-system-one-J2CJBWEH.js +2 -0
- package/dist/bundle/chunks/virtual-modules-EGJP3AJA.js +2 -0
- package/dist/bundle/chunks/xai.js +2 -0
- package/dist/bundle/cli-runtime.js +3 -0
- package/dist/bundle/cli.js +5 -0
- package/dist/bundle/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
- package/dist/bundle/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
- package/dist/bundle/native/linux/prebuilds/linux-arm64/linux-platform-x11.node +0 -0
- package/dist/bundle/native/linux/prebuilds/linux-x64/linux-platform-x11.node +0 -0
- package/dist/bundle/native/win32/prebuilds/win32-arm64/win32-platform.node +0 -0
- package/dist/bundle/native/win32/prebuilds/win32-x64/win32-platform.node +0 -0
- package/dist/core/export-html/template.css +1015 -0
- package/dist/core/export-html/template.html +55 -0
- package/dist/core/export-html/template.js +1929 -0
- package/dist/core/export-html/vendor/highlight.min.js +1213 -0
- package/dist/core/export-html/vendor/marked.min.js +78 -0
- package/dist/modes/interactive/theme/dark.json +74 -0
- package/dist/modes/interactive/theme/light.json +74 -0
- package/dist/modes/interactive/theme/system-theme.ts +579 -0
- package/dist/modes/interactive/theme/theme-controller.ts +253 -0
- package/dist/modes/interactive/theme/theme-schema.ts +145 -0
- package/dist/modes/interactive/theme/theme-tokens.ts +145 -0
- package/dist/modes/interactive/theme/theme.ts +1076 -0
- package/docs/app-server.md +479 -0
- package/docs/app-server.schema.json +8128 -0
- package/docs/cli-integration.md +106 -0
- package/docs/cli.md +393 -0
- package/docs/codemode.md +230 -0
- package/docs/compaction.md +463 -0
- package/docs/configuration.md +48 -0
- package/docs/containerization.md +143 -0
- package/docs/custom-provider.md +173 -0
- package/docs/desktop.md +73 -0
- package/docs/docs.json +236 -0
- package/docs/environment-variables.md +138 -0
- package/docs/extensions.md +314 -0
- package/docs/how-knightcode-works.md +49 -0
- package/docs/images/doom-extension.png +0 -0
- package/docs/images/interactive-mode.png +0 -0
- package/docs/images/tree-view.png +0 -0
- package/docs/index.md +39 -0
- package/docs/json.md +226 -0
- package/docs/keybindings.md +197 -0
- package/docs/llama-cpp.md +121 -0
- package/docs/mcp.md +272 -0
- package/docs/message-types.md +279 -0
- package/docs/models-configuration.md +187 -0
- package/docs/models.md +221 -0
- package/docs/nvidia-rtx-llama-cpp.md +96 -0
- package/docs/packages.md +129 -0
- package/docs/plan-mode.md +121 -0
- package/docs/prompt-templates.md +59 -0
- package/docs/providers.md +282 -0
- package/docs/quickstart.md +128 -0
- package/docs/remote.md +87 -0
- package/docs/rpc-commands.md +860 -0
- package/docs/rpc-extension-ui.md +214 -0
- package/docs/rpc.md +193 -0
- package/docs/sdk.md +197 -0
- package/docs/security.md +99 -0
- package/docs/session-format.md +358 -0
- package/docs/sessions.md +135 -0
- package/docs/settings.md +220 -0
- package/docs/shell-aliases.md +93 -0
- package/docs/skills.md +93 -0
- package/docs/slash-commands.md +78 -0
- package/docs/terminal-setup.md +242 -0
- package/docs/termux.md +117 -0
- package/docs/themes.md +140 -0
- package/docs/tmux.md +55 -0
- package/docs/tui.md +125 -0
- package/docs/usage.md +167 -0
- package/docs/virtual-models.md +114 -0
- package/docs/windows.md +67 -0
- package/examples/README.md +36 -0
- package/examples/extensions/README.md +214 -0
- package/examples/extensions/auto-commit-on-exit.ts +55 -0
- package/examples/extensions/bash-spawn-hook.ts +30 -0
- package/examples/extensions/bookmark.ts +50 -0
- package/examples/extensions/border-status-editor.ts +151 -0
- package/examples/extensions/built-in-tool-renderer.ts +225 -0
- package/examples/extensions/claude-rules.ts +89 -0
- package/examples/extensions/commands.ts +72 -0
- package/examples/extensions/confirm-destructive.ts +60 -0
- package/examples/extensions/custom-compaction.ts +118 -0
- package/examples/extensions/custom-footer.ts +66 -0
- package/examples/extensions/custom-header.ts +73 -0
- package/examples/extensions/custom-provider-anthropic/index.ts +617 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
- package/examples/extensions/custom-provider-anthropic/package.json +19 -0
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +399 -0
- package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
- package/examples/extensions/debug-provider.ts +90 -0
- package/examples/extensions/dirty-repo-guard.ts +56 -0
- package/examples/extensions/doom-overlay/README.md +46 -0
- package/examples/extensions/doom-overlay/doom/build.sh +152 -0
- package/examples/extensions/doom-overlay/doom/doomgeneric_knightcode.c +72 -0
- package/examples/extensions/doom-overlay/doom-component.ts +132 -0
- package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
- package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
- package/examples/extensions/doom-overlay/index.ts +74 -0
- package/examples/extensions/doom-overlay/wad-finder.ts +55 -0
- package/examples/extensions/dynamic-resources/SKILL.md +8 -0
- package/examples/extensions/dynamic-resources/dynamic.json +75 -0
- package/examples/extensions/dynamic-resources/dynamic.md +5 -0
- package/examples/extensions/dynamic-resources/index.ts +15 -0
- package/examples/extensions/dynamic-tools.ts +74 -0
- package/examples/extensions/entry-renderer.ts +41 -0
- package/examples/extensions/event-bus.ts +43 -0
- package/examples/extensions/file-trigger.ts +41 -0
- package/examples/extensions/git-checkpoint.ts +53 -0
- package/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/examples/extensions/github-issue-autocomplete.ts +185 -0
- package/examples/extensions/gondolin/index.ts +531 -0
- package/examples/extensions/gondolin/package-lock.json +185 -0
- package/examples/extensions/gondolin/package.json +19 -0
- package/examples/extensions/handoff.ts +190 -0
- package/examples/extensions/hello.ts +26 -0
- package/examples/extensions/hidden-thinking-label.ts +53 -0
- package/examples/extensions/inline-bash.ts +94 -0
- package/examples/extensions/input-transform-streaming.ts +39 -0
- package/examples/extensions/input-transform.ts +43 -0
- package/examples/extensions/interactive-shell.ts +196 -0
- package/examples/extensions/jev-router.ts +113 -0
- package/examples/extensions/mac-system-theme.ts +47 -0
- package/examples/extensions/message-renderer.ts +59 -0
- package/examples/extensions/minimal-mode.ts +353 -0
- package/examples/extensions/modal-editor.ts +85 -0
- package/examples/extensions/model-status.ts +31 -0
- package/examples/extensions/notify.ts +57 -0
- package/examples/extensions/overlay-qa-tests.ts +1450 -0
- package/examples/extensions/overlay-test.ts +153 -0
- package/examples/extensions/permission-gate.ts +34 -0
- package/examples/extensions/pirate.ts +47 -0
- package/examples/extensions/plan-mode/README.md +66 -0
- package/examples/extensions/plan-mode/index.ts +387 -0
- package/examples/extensions/plan-mode/utils.ts +168 -0
- package/examples/extensions/preset.ts +436 -0
- package/examples/extensions/project-trust.ts +64 -0
- package/examples/extensions/prompt-customizer.ts +49 -0
- package/examples/extensions/protected-paths.ts +30 -0
- package/examples/extensions/provider-payload.ts +18 -0
- package/examples/extensions/qna.ts +118 -0
- package/examples/extensions/question.ts +278 -0
- package/examples/extensions/questionnaire.ts +440 -0
- package/examples/extensions/rainbow-editor.ts +88 -0
- package/examples/extensions/reload-runtime.ts +37 -0
- package/examples/extensions/rpc-demo.ts +118 -0
- package/examples/extensions/sandbox/index.ts +321 -0
- package/examples/extensions/sandbox/package-lock.json +92 -0
- package/examples/extensions/sandbox/package.json +19 -0
- package/examples/extensions/send-user-message.ts +97 -0
- package/examples/extensions/session-name.ts +27 -0
- package/examples/extensions/shutdown-command.ts +63 -0
- package/examples/extensions/snake.ts +343 -0
- package/examples/extensions/space-invaders.ts +560 -0
- package/examples/extensions/ssh.ts +220 -0
- package/examples/extensions/status-line.ts +32 -0
- package/examples/extensions/structured-output.ts +65 -0
- package/examples/extensions/subagent/README.md +177 -0
- package/examples/extensions/subagent/agents/planner.md +37 -0
- package/examples/extensions/subagent/agents/reviewer.md +35 -0
- package/examples/extensions/subagent/agents/scout.md +50 -0
- package/examples/extensions/subagent/agents/worker.md +24 -0
- package/examples/extensions/subagent/agents.ts +157 -0
- package/examples/extensions/subagent/index.ts +1010 -0
- package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
- package/examples/extensions/subagent/prompts/implement.md +10 -0
- package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
- package/examples/extensions/summarize.ts +199 -0
- package/examples/extensions/system-prompt-header.ts +17 -0
- package/examples/extensions/tic-tac-toe.ts +1004 -0
- package/examples/extensions/timed-confirm.ts +70 -0
- package/examples/extensions/titlebar-spinner.ts +58 -0
- package/examples/extensions/todo.ts +294 -0
- package/examples/extensions/tool-override.ts +144 -0
- package/examples/extensions/tools.ts +146 -0
- package/examples/extensions/trigger-compact.ts +50 -0
- package/examples/extensions/truncated-tool.ts +195 -0
- package/examples/extensions/widget-placement.ts +9 -0
- package/examples/extensions/with-deps/index.ts +32 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +22 -0
- package/examples/extensions/working-indicator.ts +121 -0
- package/examples/extensions/working-message-test.ts +25 -0
- package/examples/rpc-client.ts +35 -0
- package/examples/rpc-extension-ui.ts +661 -0
- package/examples/sdk/01-minimal.ts +26 -0
- package/examples/sdk/02-custom-model.ts +49 -0
- package/examples/sdk/03-custom-prompt.ts +70 -0
- package/examples/sdk/04-skills.ts +55 -0
- package/examples/sdk/05-tools.ts +48 -0
- package/examples/sdk/06-extensions.ts +94 -0
- package/examples/sdk/07-context-files.ts +42 -0
- package/examples/sdk/08-prompt-templates.ts +51 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +34 -0
- package/examples/sdk/10-settings.ts +53 -0
- package/examples/sdk/11-sessions.ts +52 -0
- package/examples/sdk/12-full-control.ts +74 -0
- package/examples/sdk/13-session-runtime.ts +67 -0
- package/examples/sdk/14-codemode-mcp.ts +61 -0
- package/examples/sdk/README.md +141 -0
- package/package.json +15 -15
- package/bin/knightcode +0 -62
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# Extensions
|
|
2
|
+
|
|
3
|
+
Extensions are TypeScript modules that add executable behavior to KnightCode. Use one when a workflow needs tools, commands, event handlers, model providers, session state, or terminal UI rather than instructions alone.
|
|
4
|
+
|
|
5
|
+
An extension runs inside the KnightCode process with the same operating-system permissions. It can inspect prompts, tool calls, files, credentials, and session history, so load extensions only from sources you trust.
|
|
6
|
+
|
|
7
|
+
Typical extensions add an agent tool, protect paths, confirm dangerous commands, react to session events, modify context, expose a command, or display persistent status.
|
|
8
|
+
|
|
9
|
+
<a id="quick-start"></a>
|
|
10
|
+
<a id="writing-an-extension"></a>
|
|
11
|
+
<a id="create-an-extension"></a>
|
|
12
|
+
|
|
13
|
+
## Create and load an extension
|
|
14
|
+
|
|
15
|
+
An extension exports a default factory that receives `ExtensionAPI`. The factory registers capabilities for the current extension runtime.
|
|
16
|
+
|
|
17
|
+
Create `~/.knightcode/agent/extensions/hello.ts`:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import type { ExtensionAPI } from "@knightcodeai/cli";
|
|
21
|
+
|
|
22
|
+
export default function (knightcode: ExtensionAPI) {
|
|
23
|
+
knightcode.registerCommand("hello", {
|
|
24
|
+
description: "Show a greeting",
|
|
25
|
+
handler: async (name, ctx) => {
|
|
26
|
+
ctx.ui.notify(`Hello, ${name || "world"}!`, "info");
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Start KnightCode and run `/hello`. During development, load a file directly:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
knightcode --extension ./hello.ts
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
KnightCode uses `jiti`, so local TypeScript extensions do not need a separate compilation step. Use [KnightCode packages](packages.md) for distributed extensions and dependencies.
|
|
39
|
+
|
|
40
|
+
<a id="extension-locations"></a>
|
|
41
|
+
<a id="available-imports"></a>
|
|
42
|
+
<a id="choose-where-it-loads"></a>
|
|
43
|
+
|
|
44
|
+
## Add it to KnightCode
|
|
45
|
+
|
|
46
|
+
Place the extension in your user or project extensions directory. KnightCode loads direct TypeScript or JavaScript files and subdirectories containing an `index.ts` or `index.js` entry point.
|
|
47
|
+
|
|
48
|
+
Use a single file for a small extension and a directory for a multi-file implementation. Put npm dependencies in a nearby `package.json`. See [Configuration](configuration.md) for conventional locations and [Settings](settings.md#resources) for additional paths.
|
|
49
|
+
|
|
50
|
+
Reload replaces the extension runtime, so code after `await ctx.reload()` must not reuse state from the old runtime. Only personal and explicit command-line extensions can participate in the `project_trust` event that runs before project extensions load.
|
|
51
|
+
|
|
52
|
+
<a id="understand-the-lifecycle"></a>
|
|
53
|
+
|
|
54
|
+
## Respect the runtime lifecycle
|
|
55
|
+
|
|
56
|
+
The factory can be synchronous or asynchronous. KnightCode waits for an asynchronous factory before startup continues, allowing it to fetch configuration or register providers needed during startup.
|
|
57
|
+
|
|
58
|
+
Do not start processes, sockets, watchers, or timers in the factory because some invocations load extensions without starting a session.
|
|
59
|
+
Start long-lived resources from `session_start` or from the command or tool that needs them.
|
|
60
|
+
Close session-scoped resources from an idempotent `session_shutdown` handler.
|
|
61
|
+
|
|
62
|
+
A run proceeds from input and `before_agent_start`, through model, message, and tool events, to `agent_end`.
|
|
63
|
+
KnightCode counts as busy while a run starts, including the compaction check and `before_agent_start`, so messages sent meanwhile go into the starting run.
|
|
64
|
+
Automatic retries, recovery, compaction, or queued work can continue afterward.
|
|
65
|
+
<a id="agent_start--agent_end--agent_before_settle--agent_settled"></a>
|
|
66
|
+
|
|
67
|
+
`agent_before_settle` is the final actionable boundary: it can append entries and request one continuation.
|
|
68
|
+
`agent_settled` is final and notification-only; use it when an integration needs to know KnightCode will not continue automatically.
|
|
69
|
+
|
|
70
|
+
<a id="extensionapi-methods"></a>
|
|
71
|
+
|
|
72
|
+
## Choose an integration point
|
|
73
|
+
|
|
74
|
+
| Capability | Main API |
|
|
75
|
+
|---|---|
|
|
76
|
+
| Observe or modify lifecycle behavior | `knightcode.on()` |
|
|
77
|
+
| Add a model-callable operation | `knightcode.registerTool()` |
|
|
78
|
+
| Add a `/` command | `knightcode.registerCommand()` |
|
|
79
|
+
| Add a shortcut or CLI flag | `knightcode.registerShortcut()` or `knightcode.registerFlag()` |
|
|
80
|
+
| Send user or custom messages | `knightcode.sendUserMessage()` or `knightcode.sendMessage()` |
|
|
81
|
+
| Persist non-context session data | `knightcode.appendEntry()` |
|
|
82
|
+
| Change active tools, model, or thinking level | Session control methods on `knightcode` |
|
|
83
|
+
| Add a model provider | `knightcode.registerProvider()` |
|
|
84
|
+
| Add an MCP server | `knightcode.registerMcpServer()` |
|
|
85
|
+
| Route each request to a model | [`knightcode.registerVirtualModel()`](virtual-models.md) |
|
|
86
|
+
| Add terminal rendering | Renderer registration and `ctx.ui` |
|
|
87
|
+
| Communicate with another extension | `knightcode.events` |
|
|
88
|
+
|
|
89
|
+
Use the exported declarations in [`extensions/types.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/cli/src/core/extensions/types.ts) for exact event, context, tool, and result types.
|
|
90
|
+
|
|
91
|
+
## Follow the extension contracts
|
|
92
|
+
|
|
93
|
+
<a id="events"></a>
|
|
94
|
+
<a id="work-with-events"></a>
|
|
95
|
+
|
|
96
|
+
### Events and concurrency
|
|
97
|
+
|
|
98
|
+
Handlers run in extension load and registration order. `knightcode.on()` returns a function that unsubscribes that registration; changes do not affect a dispatch already in progress.
|
|
99
|
+
Some events notify; others transform data, replace results, or cancel an operation.
|
|
100
|
+
Use each event’s declared result type rather than assuming every return value has an effect.
|
|
101
|
+
|
|
102
|
+
Events cover resource discovery, sessions, agent and message lifecycle, providers, tools, and raw input.
|
|
103
|
+
|
|
104
|
+
`before_agent_start` exposes both the current prompt and its structured `systemPromptOptions`. `event.messageType` says what started the run: `"user"` for a prompt or `knightcode.sendUserMessage()`, with `prompt` and `images`; `"custom"` for `knightcode.sendMessage(..., { triggerTurn: true })`, with the starting `message` and no `prompt`. A returned `message` is added to either kind of run; check `messageType` to skip runs started by custom messages. Prefer changing prompt sections, selected tools, or guidelines so KnightCode can append a transcript delta. Returning `systemPrompt`, or setting `forceSystemPrompt`, replaces the whole prompt for that run while the transcript continues recording the structured sections. Providers receive the forced text as their leading system prompt.
|
|
105
|
+
|
|
106
|
+
`message_end` can replace a finalized message while preserving its role. `tool_call` can mutate input or block execution. `tool_result` handlers compose, with each handler seeing prior changes.
|
|
107
|
+
|
|
108
|
+
<a id="provider_stream_event"></a>
|
|
109
|
+
|
|
110
|
+
`provider_stream_event` fires for each parsed provider stream event before KnightCode normalizes it. The event identifies the provider, API, and model; `event.data` is the earliest structured value available to KnightCode, not necessarily the original HTTP bytes or SSE frame. Treat it as read-only because mutation can affect normalization. The event is notification-only and is not persisted.
|
|
111
|
+
|
|
112
|
+
Handlers are awaited in stream order, so slow handlers delay stream consumption. Handler errors are reported without changing the provider response. See [`debug-provider.ts`](../examples/extensions/debug-provider.ts) for an opt-in viewer that groups raw events by assistant message.
|
|
113
|
+
|
|
114
|
+
<a id="context_with_system"></a>
|
|
115
|
+
|
|
116
|
+
`context` transforms conversation messages without prompt and tool system messages; KnightCode restores that state afterward. Use `context_with_system` only when a request-local transformation must own the complete transcript, and keep a system message at index zero.
|
|
117
|
+
|
|
118
|
+
`turn_end` and `agent_before_settle` are actionable boundaries. Their handlers can chain proposed `custom`, `custom_message`, `context_edit`, or `compaction` entries and return `continue: true` for one next model request. Returning `end: true` ends the owning run after valid entries are committed; it overrides continuation and does not drain queued user input. `event.end` exposes the accumulated end request, which later handlers cannot undo. Guard continuation conditions because an unconditional continuation can loop. Use the exported event declarations for the complete validation and ordering contract.
|
|
119
|
+
|
|
120
|
+
<a id="cache_warming_decision"></a>
|
|
121
|
+
|
|
122
|
+
`cache_warming_decision` can override an idle prompt-cache refresh with `{ action: "warm" }` or `{ action: "stop" }`. The last handler that returns an action wins.
|
|
123
|
+
|
|
124
|
+
Tool calls from one assistant message can run in parallel.
|
|
125
|
+
Do not assume a sibling call or result exists when another tool event runs.
|
|
126
|
+
Use `ctx.signal` for nested work owned by an active turn; commands and idle session events often have no operation signal.
|
|
127
|
+
|
|
128
|
+
A `user_bash` handler that returns `undefined` passes the command to the next handler and then to local execution if no handler handles it. Returning `operations` or `result` stops propagation. A handler failure blocks the command rather than falling through to local execution.
|
|
129
|
+
|
|
130
|
+
<a id="custom-tools"></a>
|
|
131
|
+
<a id="register-tools"></a>
|
|
132
|
+
|
|
133
|
+
### Tools
|
|
134
|
+
|
|
135
|
+
A custom tool defines a name, model-facing description, TypeBox parameter schema, and `execute()` function.
|
|
136
|
+
Its result requires model-facing `content` and a `details` field for rendering or state reconstruction.
|
|
137
|
+
Use `details: undefined` when there are no structured details. If the tool makes nested model calls, include their `usage` in the result so session totals remain accurate.
|
|
138
|
+
|
|
139
|
+
Throw from `execute()` to produce a failed tool result.
|
|
140
|
+
Returning an object does not mark it as an error.
|
|
141
|
+
Return `terminate: true` only when the agent should skip its automatic follow-up after every completed tool in that batch agrees to terminate.
|
|
142
|
+
|
|
143
|
+
Use sequential execution when tools share mutable in-memory state.
|
|
144
|
+
File-mutating tools should wrap the complete read-modify-write operation with `withFileMutationQueue()`.
|
|
145
|
+
Truncate large model-facing results and tell the model where to read the complete output.
|
|
146
|
+
|
|
147
|
+
Declare `outputSchema` and return a matching `structuredContent` when the result is data. The model still receives `content`; programmatic callers such as codemode scripts receive `structuredContent` instead of the text. Tools without `outputSchema` are passed to scripts as their text content. To report a failure that still carries data, return the result with `isError: true` instead of throwing: the model sees an error, and scripts still receive `structuredContent`.
|
|
148
|
+
|
|
149
|
+
A tool can run other tools with `ctx.executeTool(name, args, { signal, onUpdate })`. Nested calls go through argument validation and the `tool_call` and `tool_result` handlers like model-issued calls, and emit `tool_execution_start`, `tool_execution_update`, and `tool_execution_end`; all of these events carry `parentToolCallId`, and their `toolCallId` is assigned by knightcode as `<parent id>/<n>`. These ids do not appear as tool calls or tool results in the transcript. Nested calls do not add transcript entries: their results only reach the calling tool, which reports them itself, for example through `onUpdate` and `details`. The session keeps a bounded record of them (name, arguments, status, duration, error; never results) as `nestedCalls` on the calling tool's result message. It is used for compaction file lists and shown in HTML exports. Arguments over 8 KiB per call or 32 KiB per tool result are omitted, at most 256 calls are kept, and `complete: false` marks a record that lost anything. The `usage` of nested results, at every depth, is added to the calling tool's result `usage`, so a tool reports only its own usage, not that of the tools it called. `ctx.tools` lists the tools `ctx.executeTool()` can call. `tool_result` handlers that redact `content` should also replace `structuredContent`; replacing only `content` drops it.
|
|
150
|
+
|
|
151
|
+
See [`hello.ts`](../examples/extensions/hello.ts), [`todo.ts`](../examples/extensions/todo.ts), [`dynamic-tools.ts`](../examples/extensions/dynamic-tools.ts), and [`truncated-tool.ts`](../examples/extensions/truncated-tool.ts).
|
|
152
|
+
|
|
153
|
+
### Tool exposure
|
|
154
|
+
|
|
155
|
+
`exposure` controls how the model reaches a tool. "Callable" means callable from other tools through `ctx.executeTool()` (`ctx.tools`), as the `codemode` tool's scripts do:
|
|
156
|
+
|
|
157
|
+
- `direct` (default): declared to the model while active, and callable while active.
|
|
158
|
+
- `model-only`: declared to the model while active, never callable. Use it for tools that orchestrate other tools or ask the user.
|
|
159
|
+
- `codemode`: callable whenever registered, and listed by the `codemode` tool. Not declared to the model unless activated explicitly.
|
|
160
|
+
- `deferred`: like `codemode`, but codemode tools do not list it; `tool_search` can find and activate it.
|
|
161
|
+
- `hidden`: registered but unreachable. Re-register a tool with `exposure: "hidden"` to withdraw it, since tools cannot be unregistered.
|
|
162
|
+
|
|
163
|
+
`namespace: { name, aliases, description, instructions }` groups related tools, as MCP servers do. Codemode tools list a namespace under one heading with its `description`. `instructions` holds longer usage guidance; it is not listed, and codemode scripts read it with `describeNamespace(name)`. `aliases` are other names scripts may look the namespace up by, for example the server name `docs` for `mcp__docs`; a name and the same name as a script identifier (`my-docs`, `my_docs`) match alike.
|
|
164
|
+
|
|
165
|
+
Registering a `direct` or `model-only` tool activates it unless `defaultActive: false` keeps it optional; the other exposures are not activated on registration. The active set (`knightcode.getActiveTools()`, `knightcode.setActiveTools()`) is the set of tools declared to the model. `knightcode.getAllTools()` reports each tool's `exposure`, `namespace`, `annotations`, and `reachesTools`.
|
|
166
|
+
|
|
167
|
+
`annotations` are hints about what a tool does, with the meaning of MCP tool annotations: `readOnlyHint`, `destructiveHint`, `idempotentHint`, and `openWorldHint`. MCP tools carry the hints their server declares. Missing hints take the MCP defaults: a tool is not read-only, and may be destructive and reach an open world. The hints are not verified, but a permission extension can use them to decide which calls to confirm. This confirms the calls Codex asks approval for:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
knightcode.on("tool_call", async (event, ctx) => {
|
|
171
|
+
const hints = knightcode.getAllTools().find((tool) => tool.name === event.toolName)?.annotations;
|
|
172
|
+
const needsApproval =
|
|
173
|
+
hints?.destructiveHint === true ||
|
|
174
|
+
(!hints?.readOnlyHint && ((hints?.destructiveHint ?? true) || (hints?.openWorldHint ?? true)));
|
|
175
|
+
if (needsApproval && !(await ctx.ui.confirm("Allow tool call?", event.toolName))) {
|
|
176
|
+
return { block: true, reason: `${event.toolName} was not approved` };
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
A tool that orchestrates other tools can adjust what the model sees while it is active with `prepareLoadout(loadout)`. It runs whenever the active tools change and receives the declared tools, the callable tools, and every registered tool with its exposure, namespace, and prompt guidelines. It returns replacement `descriptions` for declared tools (including its own) and `hiddenDeclarations`: active tools whose declarations requests leave out while they stay active and callable. The default system prompt leaves hidden tools out of its tool list and rules, and names no tool in the skills hint when the file reader is hidden, so the orchestrating tool should present their guidelines itself. `codemode` uses only this hook, `exposure`, `reachesTools`, and `ctx.executeTool()`, so another tool can implement the same behavior under a different name.
|
|
182
|
+
|
|
183
|
+
A tool that reaches other tools declares which ones a call may reach with `reachesTools(input)`: `"all"`, or the words of the input that may name them, where a word refers to every tool or namespace whose name it contains. `codemode` returns `"all"` for scripts that search or list tools and the words of the script otherwise; `tool_search` always returns `"all"`. Extensions that register tools late use it from their `tool_call` handler to finish registering the tools a call needs before it runs, as the MCP extension does for servers that are still connecting. The MCP extension also activates `codemode` or `tool_search` for MCP tools only when the tool of that name declares `reachesTools`.
|
|
184
|
+
|
|
185
|
+
### Activate tools dynamically
|
|
186
|
+
|
|
187
|
+
Register every tool first, keep optional tools inactive, and use `knightcode.setActiveTools()` from a loader tool to select the desired active tools. Names must already be registered; unknown names are ignored.
|
|
188
|
+
|
|
189
|
+
KnightCode records the initial prompt and tool set in the transcript's first system message, then appends tool and prompt changes before the next model request. Providers that cannot represent the transition receive a complete transcript checkpoint, which can invalidate the cached prefix.
|
|
190
|
+
|
|
191
|
+
### Tool rendering
|
|
192
|
+
|
|
193
|
+
A tool's `renderCall` and `renderResult` draw its calls in the interactive transcript and in HTML exports. `knightcode.registerToolRenderer((toolName, next) => renderers)` chooses renderers for calls to any tool, including tools that are not registered yet, such as MCP tools in a resumed session before their server connected. `next()` returns what the remaining resolvers (in extension load order), then the registered tool, would use, so `next() ?? mine` only fills in.
|
|
194
|
+
|
|
195
|
+
### MCP servers
|
|
196
|
+
|
|
197
|
+
`knightcode.registerMcpServer(name, config)` adds an MCP server for the current session. `config` has the shape of an `mcpServers` entry in [`mcp.json`](mcp.md): `command`, `args`, `env`, and `cwd` for stdio servers, `url`, `headers`, and `oauth` for HTTP servers, plus `exposure`, `toolExposure`, `description`, `enabled`, and `timeout`.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
knightcode.registerMcpServer("jira", { url: "https://mcp.example.com/jira", exposure: "codemode" });
|
|
201
|
+
knightcode.unregisterMcpServer("jira");
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Servers registered while the extension loads connect when the session starts, together with the `mcp.json` servers; servers registered later connect right away, and `knightcode.unregisterMcpServer()` closes the connection and makes the server's tools unreachable. Registrations are not saved: register again on every load, for example based on the extension's own settings. A server in `mcp.json` with the same name takes precedence, and `/mcp` shows the override. Registering the same name again replaces the extension's earlier registration; names registered by another extension, invalid names, and invalid configs throw.
|
|
205
|
+
|
|
206
|
+
The built-in MCP support connects registered servers. When nothing does, because another extension replaced it (see [MCP](mcp.md#other-mcp-extensions)), each registration is reported as an extension error. Other MCP extensions can connect registered servers too: read them with `knightcode.getMcpServers()` on `session_start` and handle the `mcp_servers_change` event for later changes.
|
|
207
|
+
|
|
208
|
+
<a id="extensioncontext"></a>
|
|
209
|
+
<a id="extensioncommandcontext"></a>
|
|
210
|
+
<a id="use-extension-context"></a>
|
|
211
|
+
|
|
212
|
+
### Context and session changes
|
|
213
|
+
|
|
214
|
+
`ExtensionContext` provides the working directory, mode, UI, session manager, model runtime, abort signal, context usage, and controls for compaction and shutdown.
|
|
215
|
+
Use `ctx.modelRegistry.streamSimple()` for provider-neutral nested model calls.
|
|
216
|
+
Use `ctx.modelRegistry.getAvailableClassifiers()` and `ctx.modelRegistry.classify()` to ask a classifier model structured questions, as the built-in [classifier gate](usage.md#classifier-gate) does.
|
|
217
|
+
|
|
218
|
+
Command handlers receive `ExtensionCommandContext`, which adds operations for waiting until idle, reloading, tree navigation, and session replacement.
|
|
219
|
+
These operations are command-only because calling them from lifecycle handlers can deadlock the runtime.
|
|
220
|
+
|
|
221
|
+
Use `await ctx.sendUserMessage(content, options)` in a command when completion
|
|
222
|
+
must include the dispatched run. It rejects dispatch or preflight failures and
|
|
223
|
+
resolves after command handling or complete agent settlement. During an active
|
|
224
|
+
run, a message sent with `deliverAs` is only queued: the promise resolves once
|
|
225
|
+
it is queued, not when that run settles. The replacement context's method has
|
|
226
|
+
the same contract. The originating prompt receives the nested dispatch's
|
|
227
|
+
acceptance once, before settlement; command-only completion reports `handled`. Command-handler failures are reported and rethrown rather
|
|
228
|
+
than acknowledged as successful. `knightcode.sendUserMessage()` remains
|
|
229
|
+
fire-and-forget; waiting for idle after calling it is not equivalent because
|
|
230
|
+
asynchronous preflight may still be running.
|
|
231
|
+
|
|
232
|
+
`ctx.newSession({ preserveModel: true, setup, withSession })` optionally keeps
|
|
233
|
+
the outgoing model and reasoning level instead of the host defaults. Capture
|
|
234
|
+
plain data before replacement and dispatch through `withSession`'s context.
|
|
235
|
+
|
|
236
|
+
Session replacement invalidates the old context. Capture only plain data before switching, then use the fresh context supplied to `withSession` for session-bound work.
|
|
237
|
+
|
|
238
|
+
<a id="state-management"></a>
|
|
239
|
+
<a id="persist-state"></a>
|
|
240
|
+
|
|
241
|
+
### State
|
|
242
|
+
|
|
243
|
+
Module-level variables are shared by every session in the process that loads
|
|
244
|
+
the extension, and so are the providers it registers: one session calling
|
|
245
|
+
`unregisterProvider` removes the provider for all of them. The desktop app's
|
|
246
|
+
app server runs many sessions in one process, so keep per-session state inside
|
|
247
|
+
the factory closure, not at module level. Virtual models are the exception:
|
|
248
|
+
each session keeps its own route. Active cached factories are pinned; up to
|
|
249
|
+
256 inactive factories remain. Eviction or `/reload` can re-evaluate a module
|
|
250
|
+
on a future load, so module globals are not persistent storage. Eviction
|
|
251
|
+
never tears down a live session's extension.
|
|
252
|
+
|
|
253
|
+
Choose storage based on how state participates in the conversation:
|
|
254
|
+
|
|
255
|
+
| State | Storage |
|
|
256
|
+
|---|---|
|
|
257
|
+
| Tool state that follows the active branch | Tool-result `details` |
|
|
258
|
+
| Durable data excluded from model context | `knightcode.appendEntry()` |
|
|
259
|
+
| Custom content stored and sent to the model | `knightcode.sendMessage()` |
|
|
260
|
+
| Data outside one session | External storage |
|
|
261
|
+
|
|
262
|
+
Reconstruct branch-sensitive state from `ctx.sessionManager.getBranch()` during `session_start`.
|
|
263
|
+
Do not rebuild it from every file entry because abandoned branches represent alternative histories.
|
|
264
|
+
Register an entry or message renderer when custom stored content should appear in the transcript.
|
|
265
|
+
|
|
266
|
+
<a id="custom-ui"></a>
|
|
267
|
+
<a id="mode-behavior"></a>
|
|
268
|
+
<a id="interact-with-the-user"></a>
|
|
269
|
+
<a id="account-for-each-mode"></a>
|
|
270
|
+
|
|
271
|
+
### UI and modes
|
|
272
|
+
|
|
273
|
+
`ctx.ui` provides dialogs, notifications, status text, widgets, titles, editor access, and custom components.
|
|
274
|
+
Use `ctx.ui.custom()` only when the interaction needs its own rendering and input.
|
|
275
|
+
See [Terminal UI](tui.md) for component, focus, overlay, theme, and performance guidance.
|
|
276
|
+
|
|
277
|
+
Extensions load in interactive, RPC, JSON, print, and desktop modes.
|
|
278
|
+
Desktop mode currently has no extension UI (`hasUI` is false); terminal
|
|
279
|
+
components remain unavailable even when desktop dialogs are added.
|
|
280
|
+
Interactive mode provides the complete terminal UI. The [DOOM overlay example](../examples/extensions/doom-overlay/) uses a custom overlay component to render a game frame by frame:
|
|
281
|
+
|
|
282
|
+
<p align="center"><img src="images/doom-extension.png" alt="The DOOM overlay example running over a KnightCode session" width="750"></p>
|
|
283
|
+
|
|
284
|
+
RPC can forward supported dialogs and notifications through the [RPC Extension UI protocol](rpc-extension-ui.md), but not custom terminal components; JSON and print modes have no UI.
|
|
285
|
+
Guard terminal-only behavior with `ctx.mode === "tui"` and use `ctx.hasUI` for interactions supported by interactive and RPC clients.
|
|
286
|
+
|
|
287
|
+
Keep tool and event behavior independent from rendering so non-interactive modes remain functional.
|
|
288
|
+
|
|
289
|
+
<a id="error-handling"></a>
|
|
290
|
+
<a id="handle-errors-and-shutdown"></a>
|
|
291
|
+
|
|
292
|
+
### Errors and cleanup
|
|
293
|
+
|
|
294
|
+
KnightCode reports handler errors and continues where possible. A `tool_call` handler failure blocks the tool as a fail-safe; a tool execution failure becomes an error result for the model.
|
|
295
|
+
|
|
296
|
+
Throw the exported `ExtensionStartupError` from `session_start` when an unsafe
|
|
297
|
+
runtime must refuse initialization. Binding or reload propagates it to the
|
|
298
|
+
host, and the failed session cannot prompt a provider, compact, or run
|
|
299
|
+
extension commands until successful startup/reload clears the failure. Ordinary
|
|
300
|
+
handler errors remain nonfatal.
|
|
301
|
+
|
|
302
|
+
Release resources in `session_shutdown` even when normal operation attempted cleanup.
|
|
303
|
+
Keep cleanup idempotent because cancellation, reload, session replacement, and process exit can converge on the same path.
|
|
304
|
+
Use `ctx.shutdown()` to request an orderly process shutdown.
|
|
305
|
+
|
|
306
|
+
<a id="examples-reference"></a>
|
|
307
|
+
<a id="use-examples-as-the-implementation-reference"></a>
|
|
308
|
+
|
|
309
|
+
## Examples and reference
|
|
310
|
+
|
|
311
|
+
The checked [extension examples](../examples/extensions/) cover tools, lifecycle events, commands, flags, shortcuts, state, rendering, providers, OAuth, remote execution, and terminal components.
|
|
312
|
+
Start with the smallest example matching your integration point.
|
|
313
|
+
|
|
314
|
+
Use [Custom Providers](custom-provider.md) for model-service integrations, [Terminal UI](tui.md) for custom components, and [KnightCode Packages](packages.md) to install or distribute extensions with other resources.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# How KnightCode Works
|
|
2
|
+
|
|
3
|
+
KnightCode coordinates model requests, tool execution, context assembly, and session storage. A session is KnightCode's record of a conversation, including messages, tool calls and results, model changes, compactions, and other events.
|
|
4
|
+
|
|
5
|
+
Messages and events in a session form a tree. Each path through that tree is a branch. The branch ending at the current entry is the active branch and supplies the history for the next model request.
|
|
6
|
+
|
|
7
|
+
## Agent loop
|
|
8
|
+
|
|
9
|
+
A submitted message is added to the active branch. KnightCode builds a model request from the system prompt, active branch, available tools, and model settings, then sends it through the selected provider.
|
|
10
|
+
|
|
11
|
+
The provider streams an assistant response, which can contain text and tool calls. KnightCode records the response, executes each tool call, and records the results. That completes one turn. If tool results or queued messages require another model request, KnightCode starts another turn. Otherwise, the run ends.
|
|
12
|
+
|
|
13
|
+
Steering messages enter after the current assistant turn. Follow-up messages enter after the agent has finished its pending work. Aborting stops the current run and returns queued messages to the editor.
|
|
14
|
+
|
|
15
|
+
## Context
|
|
16
|
+
|
|
17
|
+
The active branch supplies conversation history. KnightCode converts its session entries into model-compatible user, assistant, and tool-result messages.
|
|
18
|
+
|
|
19
|
+
KnightCode builds the system prompt from its base instructions and discovered context files. The request also carries tool definitions and skill descriptions.
|
|
20
|
+
|
|
21
|
+
Full skill instructions are loaded on demand. Extensions can add instructions or transform context.
|
|
22
|
+
|
|
23
|
+
Prompt templates expand editor input before it becomes a user message. Selected files, images, pasted text, and shell output can become message content.
|
|
24
|
+
|
|
25
|
+
## Sessions
|
|
26
|
+
|
|
27
|
+
Persistent sessions are JSONL files. Each tree entry has an ID and refers to its parent. The current entry identifies the active branch.
|
|
28
|
+
|
|
29
|
+
Continuing from an earlier entry creates another branch in the same file. Forking and cloning copy selected history into a new session file.
|
|
30
|
+
|
|
31
|
+
Model context is reconstructed from the active branch. Compaction inserts a summary entry that replaces older messages in subsequent model requests. The original entries remain in the session tree.
|
|
32
|
+
|
|
33
|
+
## Interfaces
|
|
34
|
+
|
|
35
|
+
Interactive mode renders session and agent events in the terminal. Print mode runs a prompt and writes the final response. JSON mode writes agent events as JSONL.
|
|
36
|
+
|
|
37
|
+
RPC mode accepts JSONL commands on stdin and writes responses and events to stdout. The TypeScript SDK creates and controls agent sessions in process.
|
|
38
|
+
|
|
39
|
+
All interfaces use the same agent and session mechanisms.
|
|
40
|
+
|
|
41
|
+
## Extensions and resources
|
|
42
|
+
|
|
43
|
+
Extensions are TypeScript modules loaded into the KnightCode process. Their factory functions register tools, commands, shortcuts, providers, event handlers, renderers, and terminal UI.
|
|
44
|
+
|
|
45
|
+
Skills provide on-demand instructions and supporting files. Prompt templates provide reusable message text. Themes provide terminal colors. KnightCode packages distribute these resources through npm or git.
|
|
46
|
+
|
|
47
|
+
## Trust and permissions
|
|
48
|
+
|
|
49
|
+
KnightCode resolves project trust before loading project settings and resources. After the trust decision and project-resource loading, KnightCode loads context files. Enabled tools use the operating-system permissions of the KnightCode process. Extensions execute inside that process.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# KnightCode
|
|
2
|
+
|
|
3
|
+
KnightCode is an extensible AI agent that works from your terminal. Give it a goal and a working folder, and it can inspect files, run commands, edit content, and work through multi-step tasks.
|
|
4
|
+
|
|
5
|
+
Use KnightCode for software development, research notes, writing projects, data files, or hobby work. You can use KnightCode as is, prompt it to adapt itself to your workflow, or build other applications powered by KnightCode using the SDK.
|
|
6
|
+
|
|
7
|
+
## Start using KnightCode
|
|
8
|
+
|
|
9
|
+
New to KnightCode? Follow the [Quickstart](quickstart.md) to install KnightCode, connect a model, and complete your first task.
|
|
10
|
+
|
|
11
|
+
If KnightCode is already installed, choose what you want to do:
|
|
12
|
+
|
|
13
|
+
- [Use KnightCode interactively](usage.md) to add files, run commands, direct ongoing work, and export results.
|
|
14
|
+
- [Choose a model](models.md) or connect a subscription, API key, local model, or compatible endpoint.
|
|
15
|
+
- [Continue or branch a session](sessions.md) to resume work or explore another approach without losing history.
|
|
16
|
+
- [Configure KnightCode](configuration.md) for your preferences, working folders, instructions, and reusable resources.
|
|
17
|
+
- [Understand how KnightCode works](how-knightcode-works.md), including tools, context, sessions, and the agent loop.
|
|
18
|
+
|
|
19
|
+
## Customize KnightCode
|
|
20
|
+
|
|
21
|
+
KnightCode can reuse prompts, load specialized instructions, add executable integrations, change its terminal interface, connect model services, and distribute these resources as packages.
|
|
22
|
+
Use the [Quickstart customization chooser](quickstart.md#choose-how-to-customize-knightcode) to select the smallest mechanism that meets your need.
|
|
23
|
+
|
|
24
|
+
## Automate or embed KnightCode
|
|
25
|
+
|
|
26
|
+
- Use [print mode](cli.md#invocation-and-output) for one-off and scripted tasks.
|
|
27
|
+
- Use [JSON event stream mode](json.md) to consume structured events from one run.
|
|
28
|
+
- Use [RPC mode](rpc.md) to control a separate KnightCode process.
|
|
29
|
+
- Use the [TypeScript SDK](sdk.md) to run KnightCode inside an application.
|
|
30
|
+
|
|
31
|
+
## Find reference and setup information
|
|
32
|
+
|
|
33
|
+
Use the reference pages to look up [CLI options](cli.md), [settings](settings.md), [providers](providers.md), [keybindings](keybindings.md), and [environment variables](environment-variables.md).
|
|
34
|
+
|
|
35
|
+
For platform-specific help, see [Terminal Setup](terminal-setup.md), [Windows](windows.md), [tmux](tmux.md), [Termux on Android](termux.md), or [Containerization](containerization.md).
|
|
36
|
+
|
|
37
|
+
## Work safely
|
|
38
|
+
|
|
39
|
+
KnightCode's tools and extensions run with the permissions of the KnightCode process. Project trust controls which project resources KnightCode loads, but it does not sandbox tool calls. Review [Security](security.md) before using untrusted files, repositories, extensions, or unattended automation.
|
package/docs/json.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# JSON Event Stream
|
|
2
|
+
|
|
3
|
+
JSON mode emits structured progress for one invocation:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
knightcode --mode json "Review this repository"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
KnightCode writes one session header followed by session events, then exits after the supplied prompts finish. RPC mode emits the same session-event shapes but has no session header because it is a bidirectional, long-lived protocol. See [RPC Mode](rpc.md).
|
|
10
|
+
|
|
11
|
+
This page is the canonical reference for events shared by JSON and RPC mode. Message values use the [shared message types](message-types.md).
|
|
12
|
+
|
|
13
|
+
## Framing and process I/O
|
|
14
|
+
|
|
15
|
+
The stream uses strict JSONL framing. Each record is one JSON object terminated by LF (`\n`). Split records only on LF and strip an optional preceding carriage return. Unicode line and paragraph separators are valid inside JSON strings and are not record boundaries.
|
|
16
|
+
|
|
17
|
+
Node.js `readline` is not suitable for this stream because it also recognizes those Unicode separators. Use a byte or UTF-8 stream decoder and split on LF.
|
|
18
|
+
|
|
19
|
+
Read stdout continuously. A reader that stops consuming records can stall KnightCode when the pipe buffer fills. Stdout is reserved for JSONL; diagnostics and application logging go to stderr.
|
|
20
|
+
|
|
21
|
+
## Session header
|
|
22
|
+
|
|
23
|
+
The first JSON-mode record is the current [session header](session-format.md#sessionheader):
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{"type":"session","version":3,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path"}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
RPC mode does not emit this record. Use [`get_state`](rpc-commands.md#get_state) for its current session ID and file.
|
|
30
|
+
|
|
31
|
+
## Event sequence
|
|
32
|
+
|
|
33
|
+
A basic run produces records like these:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{"type":"agent_start"}
|
|
37
|
+
{"type":"turn_start"}
|
|
38
|
+
{"type":"message_start","message":{"role":"user","content":"Review this repository","timestamp":1733234401000}}
|
|
39
|
+
{"type":"message_end","message":{"role":"user","content":"Review this repository","timestamp":1733234401000}}
|
|
40
|
+
{"type":"message_start","message":{"role":"assistant","content":[],"stopReason":"pending","...":"..."}}
|
|
41
|
+
{"type":"message_update","usage":{"...":"..."},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
|
|
42
|
+
{"type":"message_end","message":{"role":"assistant","...":"..."}}
|
|
43
|
+
{"type":"turn_end","message":{"role":"assistant","...":"..."},"toolResults":[]}
|
|
44
|
+
{"type":"agent_end","messages":[{"...":"..."}],"willRetry":false}
|
|
45
|
+
{"type":"agent_settled","aborted":false}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`agent_end` closes one low-level agent run. Automatic retry, overflow recovery, compaction retry, steering, or follow-up work can still continue. `agent_settled` means KnightCode has no remaining automatic work for that session-level run.
|
|
49
|
+
|
|
50
|
+
## Agent and turn events
|
|
51
|
+
|
|
52
|
+
| Event | Fields | Meaning |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `agent_start` | None | A low-level agent run started. |
|
|
55
|
+
| `agent_end` | `messages`, `willRetry` | That low-level run ended. `messages` contains messages generated by the run. |
|
|
56
|
+
| `agent_settled` | `aborted` | KnightCode will not continue automatically through retries, compaction recovery, or queued messages. `aborted` is `true` when the run ended because it was aborted. |
|
|
57
|
+
| `turn_start` | None | One assistant turn started. |
|
|
58
|
+
| `turn_end` | `message`, `toolResults` | One assistant response and its resulting tool calls finished. |
|
|
59
|
+
|
|
60
|
+
A turn is one assistant response plus any tool calls and tool results produced by that response.
|
|
61
|
+
|
|
62
|
+
## Message events
|
|
63
|
+
|
|
64
|
+
| Event | Fields | Meaning |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `message_start` | `message` | A message started. |
|
|
67
|
+
| `message_update` | `usage`, `assistantMessageEvent` | An assistant message emitted a content-block update. |
|
|
68
|
+
| `message_end` | `message` | A message completed. This is the authoritative final message. |
|
|
69
|
+
|
|
70
|
+
### Reconstruct streaming messages
|
|
71
|
+
|
|
72
|
+
Wire `message_update` records are delta-only. They omit the SDK event's cumulative `message` field and every `assistantMessageEvent.partial` snapshot so stream size remains linear.
|
|
73
|
+
|
|
74
|
+
The nested event is one of:
|
|
75
|
+
|
|
76
|
+
| Type | Fields in addition to `type` | Meaning |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `start` | None | The provider stream started; its cumulative `partial` field is removed on the wire. |
|
|
79
|
+
| `text_start` | `contentIndex` | A text block started. |
|
|
80
|
+
| `text_delta` | `contentIndex`, `delta` | Append text to the block. |
|
|
81
|
+
| `text_end` | `contentIndex`, `content` | The text block ended with authoritative content. |
|
|
82
|
+
| `thinking_start` | `contentIndex` | A thinking block started. |
|
|
83
|
+
| `thinking_delta` | `contentIndex`, `delta` | Append thinking text to the block. |
|
|
84
|
+
| `thinking_end` | `contentIndex`, `content` | The thinking block ended with authoritative content. |
|
|
85
|
+
| `toolcall_start` | `contentIndex`, `id`, `toolName` | A tool-call block started. |
|
|
86
|
+
| `toolcall_delta` | `contentIndex`, `delta` | Append serialized argument data. |
|
|
87
|
+
| `toolcall_end` | `contentIndex`, `toolCall` | The tool call ended with the complete `ToolCall`. |
|
|
88
|
+
| `done` | `reason`, `message` | The provider stream completed successfully. |
|
|
89
|
+
| `error` | `reason`, `error` | The provider stream ended with an error or abort message. |
|
|
90
|
+
|
|
91
|
+
The normal agent loop translates provider-level `start`, `done`, and `error` into `message_start` and `message_end` session events rather than emitting them as `message_update`. They remain admitted by the exported `JsonAgentSessionEvent` transformation for callers that construct a matching session event.
|
|
92
|
+
|
|
93
|
+
Use `contentIndex` to identify the content block. Buffer `delta` fields for a live display, but replace reconstructed data with the completed content in `text_end`, `thinking_end`, or `toolcall_end`. Replace the whole partial message with `message_end.message` when it arrives.
|
|
94
|
+
|
|
95
|
+
The top-level `usage` is the latest cumulative provider-reported usage for the assistant response. It can remain zero until completion when a provider does not report usage while streaming.
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{"type":"message_update","usage":{"input":100,"output":1,"cacheRead":0,"cacheWrite":0,"totalTokens":101,"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"total":0}},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello "}}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Tool execution events
|
|
102
|
+
|
|
103
|
+
| Event | Fields | Meaning |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `tool_execution_start` | `toolCallId`, `toolName`, `args` | Tool execution started. |
|
|
106
|
+
| `tool_execution_update` | `toolCallId`, `toolName`, `args`, `partialResult` | The tool reported a partial result. |
|
|
107
|
+
| `tool_execution_end` | `toolCallId`, `toolName`, `result`, `isError`, `durationMs` | Tool execution finished. `durationMs` is how long the tool's `execute()` took, measured with a monotonic clock; absent when the tool did not run. |
|
|
108
|
+
|
|
109
|
+
Use `toolCallId` to correlate the lifecycle. `partialResult` is the latest partial result supplied by the tool. Whether it replaces or extends an earlier update depends on that tool's result contract.
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{"type":"tool_execution_start","toolCallId":"call_abc123","toolName":"bash","args":{"command":"ls -la"}}
|
|
113
|
+
{"type":"tool_execution_update","toolCallId":"call_abc123","toolName":"bash","args":{"command":"ls -la"},"partialResult":{"content":[{"type":"text","text":"partial output"}],"details":{}}}
|
|
114
|
+
{"type":"tool_execution_end","toolCallId":"call_abc123","toolName":"bash","result":{"content":[{"type":"text","text":"complete output"}],"details":{}},"isError":false}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Queue and state events
|
|
118
|
+
|
|
119
|
+
| Event | Fields | Meaning |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `queue_update` | `steering`, `followUp` | The pending steering or follow-up queue changed. Both fields contain the complete current queue. |
|
|
122
|
+
| `entry_appended` | `entry` | An extension appended a custom session entry through `knightcode.appendEntry()`. |
|
|
123
|
+
| `session_info_changed` | `name` | The session display name changed. An absent `name` means it was cleared. |
|
|
124
|
+
| `thinking_level_changed` | `level` | The active thinking level changed. |
|
|
125
|
+
|
|
126
|
+
The `entry` value uses a persisted [session entry type](session-format.md#entry-types).
|
|
127
|
+
|
|
128
|
+
## Compaction events
|
|
129
|
+
|
|
130
|
+
`compaction_start` reports why compaction began:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{"type":"compaction_start","reason":"threshold"}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`reason` is `"manual"`, `"threshold"`, or `"overflow"`.
|
|
137
|
+
|
|
138
|
+
`compaction_end` contains the result when compaction succeeds:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"type": "compaction_end",
|
|
143
|
+
"reason": "threshold",
|
|
144
|
+
"result": {
|
|
145
|
+
"summary": "Summary of conversation...",
|
|
146
|
+
"firstKeptEntryId": "abc123",
|
|
147
|
+
"tokensBefore": 150000,
|
|
148
|
+
"estimatedTokensAfter": 32000,
|
|
149
|
+
"usage": {"...": "..."},
|
|
150
|
+
"details": {}
|
|
151
|
+
},
|
|
152
|
+
"aborted": false,
|
|
153
|
+
"willRetry": false
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
If compaction was aborted, `result` is absent and `aborted` is true. If it failed, `result` is absent, `aborted` is false, and `errorMessage` describes the failure. Successful overflow recovery sets `willRetry` to true before KnightCode retries the prompt.
|
|
158
|
+
|
|
159
|
+
See [Compaction and Branch Summaries](compaction.md) for result semantics.
|
|
160
|
+
|
|
161
|
+
## Retry events
|
|
162
|
+
|
|
163
|
+
Assistant-turn retry emits:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{"type":"auto_retry_start","attempt":1,"maxAttempts":3,"delayMs":2000,"errorMessage":"529 overloaded"}
|
|
167
|
+
{"type":"auto_retry_end","success":true,"attempt":2}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
On final failure, `auto_retry_end` has `success: false` and a `finalError` string.
|
|
171
|
+
|
|
172
|
+
Compaction and branch-summary retry emit:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{"type":"summarization_retry_scheduled","attempt":1,"maxAttempts":3,"delayMs":2000,"errorMessage":"terminated"}
|
|
176
|
+
{"type":"summarization_retry_attempt_start","source":"compaction","reason":"threshold"}
|
|
177
|
+
{"type":"summarization_retry_finished"}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
For a branch summary, `source` is `"branchSummary"` and `reason` is absent. The `reason` on a compaction retry is `"manual"`, `"threshold"`, or `"overflow"`.
|
|
181
|
+
|
|
182
|
+
## RPC-only events
|
|
183
|
+
|
|
184
|
+
A direct RPC [`bash`](rpc-commands.md#bash) command emits one `bash_execution_update` for each output chunk. Its optional `id` matches the command ID. The final command response can contain truncated output, but these events stream all output:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{"type":"bash_execution_update","id":"req-1","delta":"total 48\n"}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
RPC also adds `extension_error` when an extension handler throws:
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{"type":"extension_error","extensionPath":"/path/to/extension.ts","event":"tool_call","error":"Error message"}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Extension UI records are a separate RPC subprotocol, not `AgentSessionEvent` values. See [RPC Extension UI](rpc-extension-ui.md).
|
|
197
|
+
|
|
198
|
+
## TypeScript types
|
|
199
|
+
|
|
200
|
+
The SDK's `AgentSessionEvent` contains cumulative streaming snapshots for in-process consumers. JSON and RPC transform only `message_update`:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
type WithoutPartial<T> = T extends { partial: unknown } ? Omit<T, "partial"> : T;
|
|
204
|
+
|
|
205
|
+
type JsonAssistantMessageEvent<T> = T extends { type: "toolcall_start"; partial: unknown }
|
|
206
|
+
? WithoutPartial<T> & { id: string; toolName: string }
|
|
207
|
+
: WithoutPartial<T>;
|
|
208
|
+
|
|
209
|
+
type JsonAgentSessionEvent =
|
|
210
|
+
| Exclude<AgentSessionEvent, { type: "message_update" }>
|
|
211
|
+
| {
|
|
212
|
+
type: "message_update";
|
|
213
|
+
usage: Usage;
|
|
214
|
+
assistantMessageEvent: JsonAssistantMessageEvent<AssistantMessageEvent>;
|
|
215
|
+
};
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Use the exported `JsonAgentSessionEvent` type from `@knightcodeai/cli`. Its implementation is in [`json-event.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/cli/src/modes/json-event.ts).
|
|
219
|
+
|
|
220
|
+
## Example
|
|
221
|
+
|
|
222
|
+
Print completed messages from a one-shot run:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
knightcode --mode json "List files" 2>/dev/null | jq -c 'select(.type == "message_end")'
|
|
226
|
+
```
|