@knightcodeai/cli-linux-x64 0.7.0 → 0.8.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/bin/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @knightcodeai/cli
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Added
6
+
7
+ - Added `allowedFallbackModels` to Anthropic model overrides in `models.json`, so you can choose which models the server may fall back to — or set an empty array to turn server-side fallback off.
8
+
9
+ - Added webfetch and websearch tools — a page as pageable, greppable markdown, and results from DuckDuckGo or Brave Search — off until enabled with the new `/tools` command, which turns each built-in tool off, on for the session, or on by default, and for websearch also picks the provider and stores the Brave API key.
10
+
11
+ ### Changed
12
+
13
+ - Changed the system prompt and tool set to live in the transcript instead of being rewritten behind it. A session records when its instructions changed or tools became available, resuming or moving between branches restores that state, and providers that support it keep their cached prompt prefix across the change. Extensions can replace individual prompt sections through `systemPromptOptions.sections`, and the deferred-tool loading path is replaced by mid-conversation tool additions on the models that accept them.
14
+
15
+ - Changed a failed copy to say why: instead of a bare "Copy failed" flash, the message now names the missing clipboard backend — `wl-clipboard`, `xclip`/`xsel` or the Termux API package — and stays on screen for five seconds.
16
+
17
+ ### Fixed
18
+
19
+ - Fixed a `user_bash` handler that throws or returns a malformed result silently falling back to the local shell — the command is now reported as failed instead of running somewhere the extension meant to prevent. A handler must return `undefined`, exactly one of `{ operations }` or `{ result }`, and nothing else.
20
+
21
+ - Fixed Baseten requests to carry session-affinity headers so a conversation keeps hitting the same replica and benefits from automatic prompt caching.
22
+
23
+ - Fixed Bedrock cost reporting to bill one-hour cache writes at their higher rate instead of charging every cache write at the five-minute rate.
24
+
25
+ - Fixed a local copy reporting success when no clipboard backend actually took the text: the terminal-escape fallback now only counts in a remote session, where it is the terminal that owns the clipboard.
26
+
27
+ - Fixed the package's public types so extension authors can import the event and result types their hooks receive, such as `ModelSelectEvent`, `ThinkingLevelSelectEvent` and the `*Result` types, instead of redeclaring them.
28
+
29
+ - Fixed the thinking levels offered for Gemini models: they now follow the reasoning efforts each model actually advertises instead of a version-number guess, so newer Flash and Pro models expose their real low/medium/high range.
30
+
31
+ - Fixed resuming a session by its exact ID reading every transcript in the session directory first, which made startup slow in directories with long histories.
32
+
3
33
  ## 0.7.0
4
34
 
5
35
  ### Added
@@ -406,25 +406,31 @@ For providers with non-standard APIs, implement `streamSimple`. Study the existi
406
406
 
407
407
  ### Stream Pattern
408
408
 
409
- All providers follow the same pattern:
409
+ All providers follow the same pattern. The context is a normalized transcript: the system prompt and tool declarations live in its system messages, so read them with `getCurrentSystemPrompt(context.messages)` and `getCurrentTools(context.messages)` rather than expecting `context.systemPrompt` or `context.tools`. Models that accept system messages mid-conversation can send them in place; otherwise call `collapseSystemMessages(context)` first to fold later system messages into the leading one.
410
410
 
411
411
  ```typescript
412
412
  import {
413
413
  type AssistantMessage,
414
414
  type AssistantMessageEventStream,
415
- type Context,
416
415
  type Model,
417
416
  type SimpleStreamOptions,
417
+ type TranscriptContext,
418
418
  calculateCost,
419
+ collapseSystemMessages,
419
420
  createAssistantMessageEventStream,
421
+ getCurrentSystemPrompt,
422
+ getCurrentTools,
420
423
  } from "@knightcode/ai";
421
424
 
422
425
  function streamMyProvider(
423
426
  model: Model<any>,
424
- context: Context,
427
+ context: TranscriptContext,
425
428
  options?: SimpleStreamOptions
426
429
  ): AssistantMessageEventStream {
427
430
  const stream = createAssistantMessageEventStream();
431
+ const transcript = collapseSystemMessages(context);
432
+ const systemPrompt = getCurrentSystemPrompt(transcript.messages);
433
+ const tools = getCurrentTools(transcript.messages);
428
434
 
429
435
  (async () => {
430
436
  // Initialize output message
@@ -668,10 +674,10 @@ interface ProviderConfig {
668
674
  /** API type for streaming. Required at provider or model level when defining models. */
669
675
  api?: Api;
670
676
 
671
- /** Custom streaming implementation for non-standard APIs. */
677
+ /** Custom streaming implementation for non-standard APIs. Receives a normalized transcript. */
672
678
  streamSimple?: (
673
679
  model: Model<Api>,
674
- context: Context,
680
+ context: TranscriptContext,
675
681
  options?: SimpleStreamOptions
676
682
  ) => AssistantMessageEventStream;
677
683
 
@@ -93,6 +93,7 @@ These variables are read by KnightCode itself:
93
93
  | `KNIGHTCODE_IMAGE_PROTOCOL` | Override inline image detection with `kitty`, `iterm2`, `none`, or `auto` |
94
94
  | `KNIGHTCODE_TRUE_COLOR` | Override truecolor detection with `1`, `0`, or `auto` |
95
95
  | `KNIGHTCODE_TUI_ESC_TIMEOUT` | How long to wait after a lone ESC before treating it as Escape, in milliseconds; defaults to `100` over SSH and `10` otherwise. Increase if Alt-key input is misread as Escape |
96
+ | `BRAVE_API_KEY` | Brave Search key for `websearch` when none is stored with `/tools`; see [Web tools](usage.md#web-tools) |
96
97
  | `VISUAL`, `EDITOR` | External editor fallback when `externalEditor` is unset |
97
98
  | `HTTP_PROXY`, `HTTPS_PROXY` | Proxy outbound HTTP requests |
98
99
 
@@ -538,10 +538,13 @@ knightcode.on("before_agent_start", async (event, ctx) => {
538
538
  // event.systemPrompt - current chained system prompt for this handler
539
539
  // (includes changes from earlier before_agent_start handlers)
540
540
  // event.systemPromptOptions - structured options used to build the system prompt
541
- // .customPrompt - any custom system prompt (from --system-prompt, SYSTEM.md, or custom templates)
541
+ // .customPrompt - exact prompt prefix from --system-prompt, SYSTEM.md, or custom templates
542
+ // .forceSystemPrompt - optional exact replacement for the complete prompt
542
543
  // .selectedTools - tools currently active in the prompt
543
544
  // .toolSnippets - one-line descriptions for each tool
544
- // .promptGuidelines - custom guideline bullets
545
+ // .toolGuidelines - guideline bullets keyed by tool name
546
+ // .promptGuidelines - additional custom guideline bullets
547
+ // .sections - custom XML-wrapped sections keyed by tag name
545
548
  // .appendSystemPrompt - text from --append-system-prompt flags
546
549
  // .cwd - working directory
547
550
  // .contextFiles - AGENTS.md files and other loaded context files
@@ -560,7 +563,7 @@ knightcode.on("before_agent_start", async (event, ctx) => {
560
563
  });
561
564
  ```
562
565
 
563
- The `systemPromptOptions` field gives extensions access to the same structured data KnightCode uses to build the system prompt. This lets you inspect what KnightCode has loaded — custom prompts, guidelines, tool snippets, context files, skills — without re-discovering resources or re-parsing flags. Use it when your extension needs to make deep, informed changes to the system prompt while respecting user-provided configuration.
566
+ The `systemPromptOptions` field gives extensions access to the same structured data KnightCode uses to build the system prompt. Collections are mutable. Prefer changing `sections`, `selectedTools`, or `promptGuidelines`: KnightCode diffs the resulting prompt sections against what the model already has and appends one system message patching only the changed sections. Returning `systemPrompt`, or setting `forceSystemPrompt`, replaces the whole prompt with a single untagged `preamble` section. Tool selection changes update both the prompt contributions and executable provider tools; calling `knightcode.setActiveTools()` inside the handler has the same effect as editing `selectedTools`. Models that accept system messages mid-conversation receive the patch in place and keep their cached prefix; other models get the replayed prompt as their system prompt, which is a cache miss once per change.
564
567
 
565
568
  Inside `before_agent_start`, `event.systemPrompt` and `ctx.getSystemPrompt()` both reflect the chained system prompt as of the current handler. Later `before_agent_start` handlers can still modify it again.
566
569
 
@@ -906,6 +909,8 @@ knightcode.on("user_bash", (event, ctx) => {
906
909
  });
907
910
  ```
908
911
 
912
+ Returning `undefined` continues to the next handler, then local execution if none handles the event. A valid result stops propagation: `operations` executes the command through the supplied backend, while `result` records the completed command without executing it.
913
+
909
914
  ### Input Events
910
915
 
911
916
  #### input
@@ -1125,7 +1130,7 @@ const options = ctx.getSystemPromptOptions();
1125
1130
  const contextPaths = options.contextFiles?.map((file) => file.path) ?? [];
1126
1131
  ```
1127
1132
 
1128
- This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom prompt, active tools, tool snippets, prompt guidelines, appended system prompt text, cwd, loaded context files, and loaded skills. It may include full context file contents, so treat it as sensitive extension-local data and avoid exposing it through command lists, logs, or autocomplete metadata.
1133
+ This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom or forced prompt, active tools, tool snippets, per-tool and custom rules, custom sections, appended prompt text, cwd, loaded context files, and loaded skills. It may include full context file contents, so treat it as sensitive extension-local data and avoid exposing it through command lists, logs, or autocomplete metadata.
1129
1134
 
1130
1135
  This reports the current base prompt inputs. It does not include per-turn `before_agent_start` chained system-prompt changes, later `context` event message mutations, or `before_provider_request` payload rewrites.
1131
1136
 
@@ -2370,42 +2375,13 @@ If a slot renderer is not defined or throws:
2370
2375
 
2371
2376
  ### Dynamic Tool Loading
2372
2377
 
2373
- Extensions can register many tools while keeping only a small initial set active. A tool can then add more tools with `knightcode.setActiveTools()` during execution. KnightCode detects purely additive changes, records the newly available tool names on that tool result, and applies the updated active set before the next model request.
2374
-
2375
- This works with every model. Models with native deferred-loading support preserve the stable prompt prefix and load the new definitions at the tool-result position. Other models use the fallback described below.
2378
+ Extensions can register many tools while keeping only a small initial set active. A tool can then change the active set with `knightcode.setActiveTools()` during execution. KnightCode stores the initial prompt and tool loadout in the transcript's first system message, then appends tool and prompt deltas before the next model request. Providers that cannot represent a transition receive a complete transcript checkpoint, which may invalidate the cached prefix.
2376
2379
 
2377
2380
  The lifecycle is:
2378
2381
 
2379
2382
  1. Register every tool with `knightcode.registerTool()` so it appears in `knightcode.getAllTools()`.
2380
2383
  2. Keep loader tools, such as `search_tools`, active and leave searchable tools inactive.
2381
- 3. During loader execution, call `knightcode.setActiveTools([...currentTools, ...matchingTools])`. The change must be additive: do not remove currently active tools in the same call.
2382
- 4. KnightCode records which tools were added on the loader's tool result.
2383
- 5. Before the next model response, KnightCode exposes the added definitions using native deferred loading when supported, or the normal active tool list otherwise.
2384
-
2385
- You do not need to return provider-specific tool references or mark the loader as a special search tool. The active-tool change is the signal. Names passed to `knightcode.setActiveTools()` must already be registered; unknown names are ignored.
2386
-
2387
- #### Models with native deferred loading
2388
-
2389
- - **Anthropic**
2390
- - **Models:** Sonnet, Opus, Fable version 4.5 or newer (without Haiku)
2391
- - **Native representation:** Deferred definitions use `defer_loading`; the load point uses `tool_reference` content.
2392
- - **Fireworks Messages API**
2393
- - **Native representation:** Deferred definitions use `defer_loading`; the load point uses `tool_reference` content.
2394
- - **Loader names:** Use `ToolSearch` or `tool_search` for prefix deferral. Other loader names still work, but Fireworks includes the loaded schemas in the initial tool prefix, losing the cache benefit.
2395
- - This does not change API routing: Fireworks GLM models and Kimi K3 use Chat Completions, not Messages.
2396
- - **OpenAI**
2397
- - **Models:** `gpt-5.4` and newer family
2398
- - **Native representation:** KnightCode adds completed client `tool_search_call` and `tool_search_output` items at the load point.
2399
-
2400
- For a verified custom model or proxy, native handling can be enabled with `compat.supportsToolReferences: true` for `anthropic-messages`, or `compat.supportsToolSearch: true` for `openai-responses` and `openai-codex-responses`. Leave these disabled unless the endpoint and model accept the corresponding native protocol.
2401
-
2402
- #### Fallback behavior
2403
-
2404
- For all other models and providers, dynamic activation still works: KnightCode sends the complete current active tool list normally on the next request. The model can call the newly activated tools, but adding their definitions may invalidate the provider's cached prompt prefix.
2405
-
2406
- KnightCode also uses this safe fallback when the active set is not purely additive, such as replacing one group of tools with another. Tool removals therefore work, but they do not use deferred loading.
2407
-
2408
- For the best cache behavior, keep the loader tool active for the whole session and add tools instead of replacing the active set. Also note that activating a tool with `promptSnippet` or `promptGuidelines` rebuilds the system prompt; that system-prompt change can invalidate the prefix even when the provider supports deferred schemas. Lazily loaded tools should usually rely on their tool `description` and omit active-only prompt metadata.
2384
+ 3. During loader execution, call `knightcode.setActiveTools()` with the desired active tool names. Names must already be registered; unknown names are ignored.
2409
2385
 
2410
2386
  #### Search tool example
2411
2387
 
@@ -2507,7 +2483,7 @@ export default function (knightcode: ExtensionAPI) {
2507
2483
  }
2508
2484
  ```
2509
2485
 
2510
- When `search_tools` adds a match, the model receives that definition on the immediately following request. On a native-capable model the definition is anchored after the search result without changing the initial tool-schema prefix. On other models it appears in the normal tool list on that same following request.
2486
+ When `search_tools` adds a match, the model receives the complete updated tool list on the immediately following request.
2511
2487
 
2512
2488
  ## Custom UI
2513
2489
 
@@ -436,6 +436,7 @@ Built-in Anthropic models enable `supportsStrictTools` in their model metadata.
436
436
  | `supportsMidConvoEffort` | Whether the exact Claude model transport supports per-turn effort system messages and thinking binding controls. KnightCode persists native effort levels and always sends `drop_block` when enabled. Default: `false`. |
437
437
  | `allowEmptySignature` | Whether to replay empty thinking signatures as `signature: ""` instead of converting thinking to text. Default: `false`. |
438
438
  | `supportsStrictTools` | Whether the provider accepts strict JSON-schema tool definitions. Default: `false`; built-in Anthropic models enable it in generated metadata. |
439
+ | `allowedFallbackModels` | Up to three server-side fallback models, each with `provider`, `model`, and complete `cost` metadata. An empty array disables fallback. |
439
440
 
440
441
  ## OpenAI Compatibility
441
442
 
@@ -482,7 +483,6 @@ For providers with partial OpenAI compatibility, use the `compat` field.
482
483
  | `sessionAffinityFormat` | For `openai-completions` and `openai-responses`, the session-affinity header format: `openai` sends `session_id`/`x-client-request-id` (completions also `x-session-affinity`), `openai-nosession` omits the underscore-containing `session_id` header, `openrouter` sends `x-session-id`. Does not affect the `prompt_cache_key` body param. Default: auto-detected. |
483
484
  | `supportsStrictMode` | Whether the provider accepts strict JSON-schema function tool definitions. Defaults depend on the API; built-in OpenAI models carry explicit capability metadata. |
484
485
  | `supportsOpenAIGrammarTools` | Whether OpenAI-compatible APIs emit custom Lark/regex grammar tools. When `false`, grammar-constrained tools fall back to normal function tools. Default: `false`; the built-in model catalog enables it for GPT-5+ models on OpenAI, OpenAI Codex, Azure OpenAI, GitHub Copilot, opencode, and Cloudflare AI Gateway. |
485
- | `deferredToolsMode` | Use provider-specific deferred tool serialization. Currently only `"kimi"` is supported for Kimi's OpenAI-compatible Chat Completions format. |
486
486
  | `supportsLongCacheRetention` | Whether the provider accepts long cache retention when cache retention is `long`: `prompt_cache_options.ttl: "30m"` for GPT-5.6+ Responses models, `prompt_cache_retention: "24h"` for earlier OpenAI models, or `cache_control.ttl: "1h"` when `cacheControlFormat` is `anthropic`. Default: `true`. |
487
487
  | `openRouterRouting` | OpenRouter provider routing preferences. This object is sent as-is in the `provider` field of the [OpenRouter API request](https://openrouter.ai/docs/guides/routing/provider-selection). |
488
488
  | `vercelGatewayRouting` | Vercel AI Gateway routing config for provider selection (`only`, `order`) |
package/bin/docs/sdk.md CHANGED
@@ -246,8 +246,8 @@ const state = session.agent.state;
246
246
  // state.messages: AgentMessage[] - conversation history
247
247
  // state.model: Model - current model
248
248
  // state.thinkingLevel: ThinkingLevel - current thinking level
249
- // state.systemPrompt: string - system prompt
250
- // state.tools: AgentTool[] - available tools
249
+ // state.systemPrompt: string - read-only, replayed from the transcript's system messages
250
+ // state.tools: AgentTool[] - executable tools; changes are declared to the model before the next request
251
251
  // state.streamingMessage?: AgentMessage - current partial assistant message
252
252
  // state.errorMessage?: string - latest assistant error
253
253
 
@@ -77,6 +77,14 @@ interface ToolCall {
77
77
  ### Base Message Types (from @knightcode/ai)
78
78
 
79
79
  ```typescript
80
+ interface SystemMessage {
81
+ role: "system";
82
+ content: string | TextContent[];
83
+ toolsAdded?: Tool[];
84
+ toolsRemoved?: Array<{ name: string }>;
85
+ timestamp: number; // Unix ms
86
+ }
87
+
80
88
  interface UserMessage {
81
89
  role: "user";
82
90
  content: string | (TextContent | ImageContent)[];
@@ -109,7 +117,6 @@ interface ToolResultMessage {
109
117
  content: (TextContent | ImageContent)[];
110
118
  details?: any; // Tool-specific metadata
111
119
  usage?: Usage; // Nested LLM work performed by the tool
112
- addedToolNames?: string[];
113
120
  isError: boolean;
114
121
  timestamp: number;
115
122
  }
@@ -177,6 +184,7 @@ interface CompactionSummaryMessage {
177
184
 
178
185
  ```typescript
179
186
  type AgentMessage =
187
+ | SystemMessage
180
188
  | UserMessage
181
189
  | AssistantMessage
182
190
  | ToolResultMessage
@@ -217,7 +225,14 @@ For sessions with a parent (created via `/fork`, `/clone`, or `newSession({ pare
217
225
 
218
226
  ### SessionMessageEntry
219
227
 
220
- A message in the conversation. The `message` field contains an `AgentMessage`.
228
+ A message in the conversation. The `message` field contains an `AgentMessage`. System messages carry the prompt and tool loadout: the first request of a session persists one with every prompt section and tool declaration, and later changes persist as system messages that patch `sections` by name (`null` removes one) and list `toolsAdded`/`toolsRemoved`. Replaying them in order yields the current prompt and tools; there is no separate prompt state entry.
229
+
230
+ ```json
231
+ {"type":"message","id":"a0b1c2d3","parentId":null,"timestamp":"2024-12-03T14:00:00.000Z","message":{"role":"system","content":"","sections":{"preamble":"You are an expert coding assistant...","tools":"<tools>\n- read: ...\n</tools>","cwd":"/project"},"toolsAdded":[{"name":"read","description":"...","parameters":{}}],"timestamp":1733234400000}}
232
+ {"type":"message","id":"d4e5f6g7","parentId":"c3d4e5f6","timestamp":"2024-12-03T14:04:00.000Z","message":{"role":"system","content":"","sections":{"skills":"<skills>...</skills>"},"toolsRemoved":[{"name":"write"}],"timestamp":1733234640000}}
233
+ ```
234
+
235
+ Sessions created before system messages existed have no leading system message; the first request declares the current prompt as a later system message, which replays the same way.
221
236
 
222
237
  ```json
223
238
  {"type":"message","id":"a1b2c3d4","parentId":"prev1234","timestamp":"2024-12-03T14:00:01.000Z","message":{"role":"user","content":"Hello","timestamp":1733234401000}}
@@ -243,15 +258,16 @@ Emitted when the user changes the thinking/reasoning level.
243
258
 
244
259
  ### CompactionEntry
245
260
 
246
- Created when context is compacted. Stores a summary of earlier messages.
261
+ Created when context is compacted. Stores a summary of earlier messages and a complete system prompt/tool checkpoint.
247
262
 
248
263
  ```json
249
- {"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000}
264
+ {"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000,"systemMessage":{"role":"system","content":"You are a coding assistant.","toolsAdded":[],"timestamp":1733235000000}}
250
265
  ```
251
266
 
252
267
  `firstKeptEntryId` is required. It identifies the first entry retained from before the compaction entry. When rebuilding context, KnightCode replaces older summarized entries with the compaction summary and keeps the range beginning at this entry.
253
268
 
254
269
  Optional fields:
270
+ - `systemMessage`: The replayed prompt sections and tool declarations at the compaction boundary; it becomes the leading system message of the compacted context, and system messages among the kept entries are dropped in its favor. It is absent on older session entries.
255
271
  - `usage`: LLM usage from generating the summary; included in session token and cost totals
256
272
  - `details`: Implementation-specific data (e.g., `{ readFiles: string[], modifiedFiles: string[] }` for default, or custom data for extensions)
257
273
  - `fromHook`: `true` if generated by an extension, `false`/`undefined` if knightcode-generated (legacy field name)
@@ -336,7 +352,7 @@ Entries normally form one tree, but navigation APIs can create multiple roots:
336
352
  1. Collects all entries on the path
337
353
  2. If one or more `CompactionEntry` values are on the path, uses the latest one:
338
354
  - Includes the compaction entry first
339
- - Includes entries from `firstKeptEntryId` up to, but not including, the compaction entry
355
+ - Includes non-system entries from `firstKeptEntryId` up to, but not including, the compaction entry
340
356
  - Includes entries after the compaction entry
341
357
  3. Preserves non-message entries in the selected range so interactive mode can render them
342
358
 
@@ -345,12 +361,12 @@ Entries normally form one tree, but navigation APIs can create multiple roots:
345
361
  1. Extracts current model and thinking level settings from the full path
346
362
  2. Converts selected entries to messages:
347
363
  - `message` -> stored `AgentMessage`
348
- - `compaction` -> `compactionSummary`
364
+ - `compaction` -> complete system checkpoint followed by `compactionSummary`
349
365
  - `branch_summary` -> `branchSummary`
350
366
  - `custom_message` -> `CustomMessage`
351
367
  - `custom` -> no context message
352
368
 
353
- The compaction summary replaces entries before `firstKeptEntryId`. The retained entries and all entries after the compaction remain available to the LLM.
369
+ The compaction summary replaces entries before `firstKeptEntryId`. Pre-compaction system messages are folded into the complete checkpoint rather than replayed from the retained range. Retained non-system entries and all entries after the compaction remain available to the LLM.
354
370
 
355
371
  ## Parsing Example
356
372
 
@@ -279,6 +279,8 @@ On Windows, select `powershell` instead of `bash`, or include both:
279
279
 
280
280
  An empty array starts with no built-in tools while preserving extension and SDK custom tools. `--tools` replaces this behavior with a strict allowlist for all tools, `--no-tools` disables all tools, and `--no-builtin-tools` disables the built-in defaults. `--exclude-tools` filters the resulting list. A project `defaultTools` array replaces the global array.
281
281
 
282
+ The [web tools](usage.md#web-tools) `webfetch` and `websearch` are not part of `defaultTools`. `/tools` turns them on and stores their settings, including the search provider and Brave key, in `~/.knightcode/agent/tools.json`.
283
+
282
284
  ### Sessions
283
285
 
284
286
  | Setting | Type | Default | Description |
package/bin/docs/usage.md CHANGED
@@ -42,6 +42,7 @@ Type `/` in the editor to open command completion. Extensions can register custo
42
42
  | `/thinking` | Switch thinking level; Ctrl+S or Ctrl+D in the picker saves the startup default |
43
43
  | `/scoped-models` | Enable/disable models for Ctrl+P cycling |
44
44
  | `/settings` | Theme, message delivery, transport, and other preferences |
45
+ | [`/tools`](#web-tools) | Turn `webfetch` and `websearch` off, on for this session, or on by default; pick the search provider and store its key |
45
46
  | `/resume` | Pick from previous sessions |
46
47
  | `/new` | Start a new session |
47
48
  | `/name <name>` | Set session display name |
@@ -60,6 +61,37 @@ Type `/` in the editor to open command completion. Extensions can register custo
60
61
  | `/changelog` | Display version history |
61
62
  | `/quit` | Quit knightcode |
62
63
 
64
+ ## Web Tools
65
+
66
+ Two tools give the agent read access to the web. Both ship disabled; turn them on with `/tools`.
67
+
68
+ | Tool | What it does |
69
+ |------|--------------|
70
+ | `webfetch` | Fetches a URL and returns the page as markdown, 400 lines at a time. The agent pages with `offset`/`limit` like `read`, or passes `grep` to get only matching lines. Responses are cached for 15 minutes, capped at 5 MB, and time out after 30 seconds. Private, loopback, and link-local addresses are refused. |
71
+ | `websearch` | Searches the web and returns up to 10 results (default 5) as title, URL, and snippet. DuckDuckGo needs no key but may rate-limit; Brave Search needs an API key. |
72
+
73
+ `/tools` lists each tool with its current state; pick one to open its settings panel. **Status** cycles through three states:
74
+
75
+ | State | Effect |
76
+ |-------|--------|
77
+ | Disabled | The tool is not offered to the model |
78
+ | Enabled for this session | On until knightcode exits, including across `/new`, `/resume`, and `/fork`; nothing is written to disk |
79
+ | Enabled by default | On in every session |
80
+
81
+ The `websearch` panel adds two rows: **Provider** (`duckduckgo` or `brave`) and **Brave API key**. Choosing Brave without a stored key opens the key prompt at once. Get a key at https://brave.com/search/api/; the free plan is enough. The key is also read from `BRAVE_API_KEY` when none is stored, but the provider only switches to Brave when you pick it. Keys show masked in the panel.
82
+
83
+ The same changes work without the panel:
84
+
85
+ ```bash
86
+ /tools websearch on # this session
87
+ /tools webfetch always # every session
88
+ /tools webfetch off
89
+ ```
90
+
91
+ Settings are stored in `~/.knightcode/agent/tools.json`, owner-readable only because it can hold the Brave key. `--tools` and `--exclude-tools` still apply: a tool excluded on the command line stays off whatever `/tools` says.
92
+
93
+ Fetched pages and search results are marked as untrusted in the tool output so the model treats instructions inside them as data, but treat the tools like any other network access: a fetched page can still influence what the agent does next.
94
+
63
95
  ## Message Queue
64
96
 
65
97
  You can submit messages while the agent is still working:
@@ -212,7 +244,7 @@ cat README.md | knightcode -p "Summarize this text"
212
244
  | `--no-builtin-tools`, `-nbt` | Disable built-in tools but keep extension/custom tools enabled |
213
245
  | `--no-tools`, `-nt` | Disable all tools |
214
246
 
215
- Built-in tools: `read`, `bash`, `powershell` (Windows), `edit`, `write`, `grep`, `find`, `ls`.
247
+ Built-in tools: `read`, `bash`, `powershell` (Windows), `edit`, `write`, `grep`, `find`, `ls`. The [web tools](#web-tools) `webfetch` and `websearch` are off until enabled with `/tools`.
216
248
 
217
249
  ### Resource Options
218
250
 
package/bin/knightcode CHANGED
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/bin/knightcode
3
- size: 116660517 bytes
4
- sha256: 739bf41e41c13fb7f6240996c98de31aaa97659fcf6a790cd6134676fcdb8235
3
+ size: 117447166 bytes
4
+ sha256: 7d7e0678a4920ce09880c0016816a1a91fd224d7f3e2e110851deb0939894967
package/bin/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knightcodeai/cli",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "KnightCode — a local, BYOK terminal coding agent powered by OpenRouter.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -37,11 +37,11 @@
37
37
  "test": "vitest --run"
38
38
  },
39
39
  "optionalDependencies": {
40
- "@knightcodeai/cli-linux-x64": "0.7.0",
41
- "@knightcodeai/cli-linux-arm64": "0.7.0",
42
- "@knightcodeai/cli-darwin-x64": "0.7.0",
43
- "@knightcodeai/cli-darwin-arm64": "0.7.0",
44
- "@knightcodeai/cli-win32-x64": "0.7.0"
40
+ "@knightcodeai/cli-linux-x64": "0.8.0",
41
+ "@knightcodeai/cli-linux-arm64": "0.8.0",
42
+ "@knightcodeai/cli-darwin-x64": "0.8.0",
43
+ "@knightcodeai/cli-darwin-arm64": "0.8.0",
44
+ "@knightcodeai/cli-win32-x64": "0.8.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@agentclientprotocol/sdk": "1.4.0",
@@ -50,6 +50,7 @@
50
50
  "@knightcode/client": "workspace:*",
51
51
  "@knightcode/protocol": "workspace:*",
52
52
  "@knightcode/remote": "workspace:*",
53
+ "@knightcode/tools": "workspace:*",
53
54
  "@knightcode/server": "workspace:*",
54
55
  "@knightcode/session-backend-sqlite": "workspace:*",
55
56
  "@knightcode/tui": "workspace:*",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knightcodeai/cli-linux-x64",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",