kward 0.77.0 → 0.79.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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +7 -2
  3. data/.github/workflows/pages.yml +1 -1
  4. data/CHANGELOG.md +50 -0
  5. data/Gemfile.lock +2 -2
  6. data/README.md +5 -2
  7. data/doc/agent-tools.md +1 -1
  8. data/doc/code-search.md +9 -6
  9. data/doc/configuration.md +106 -1
  10. data/doc/extensibility.md +2 -0
  11. data/doc/getting-started.md +1 -1
  12. data/doc/local-models.md +130 -0
  13. data/doc/permissions.md +180 -0
  14. data/doc/plugins.md +58 -0
  15. data/doc/releasing.md +1 -1
  16. data/doc/rpc.md +73 -1
  17. data/doc/sandboxing.md +120 -0
  18. data/doc/security.md +15 -5
  19. data/doc/skills.md +10 -0
  20. data/doc/tabs.md +4 -3
  21. data/doc/web-search.md +4 -2
  22. data/doc/workspace-tools.md +3 -3
  23. data/kward.gemspec +1 -1
  24. data/lib/kward/auth/anthropic_oauth.rb +2 -2
  25. data/lib/kward/auth/github_oauth.rb +3 -3
  26. data/lib/kward/auth/oauth_helpers.rb +4 -2
  27. data/lib/kward/auth/openai_oauth.rb +2 -1
  28. data/lib/kward/cli/doctor.rb +21 -0
  29. data/lib/kward/cli/plugins.rb +22 -0
  30. data/lib/kward/cli/rendering.rb +7 -1
  31. data/lib/kward/cli/runtime_helpers.rb +15 -1
  32. data/lib/kward/cli/settings.rb +66 -4
  33. data/lib/kward/cli/slash_commands.rb +109 -1
  34. data/lib/kward/cli/tabs.rb +140 -34
  35. data/lib/kward/cli.rb +31 -10
  36. data/lib/kward/config_files.rb +90 -1
  37. data/lib/kward/conversation.rb +14 -1
  38. data/lib/kward/hooks/http_handler.rb +2 -1
  39. data/lib/kward/http.rb +18 -0
  40. data/lib/kward/local_command_runner.rb +2 -2
  41. data/lib/kward/model/client.rb +173 -15
  42. data/lib/kward/model/model_info.rb +11 -1
  43. data/lib/kward/model/payloads.rb +7 -1
  44. data/lib/kward/model/stream_parser.rb +58 -26
  45. data/lib/kward/openrouter_model_cache.rb +2 -1
  46. data/lib/kward/pan/index.html.erb +50 -0
  47. data/lib/kward/pan/server.rb +49 -2
  48. data/lib/kward/permissions/policy.rb +171 -0
  49. data/lib/kward/plugin_registry.rb +54 -2
  50. data/lib/kward/prompt_interface/approval_prompt.rb +62 -0
  51. data/lib/kward/prompt_interface/editor/controller.rb +36 -3
  52. data/lib/kward/prompt_interface/question_prompt.rb +12 -3
  53. data/lib/kward/prompt_interface.rb +20 -0
  54. data/lib/kward/prompts/commands.rb +2 -0
  55. data/lib/kward/prompts.rb +16 -5
  56. data/lib/kward/rpc/plugin_chat_manager.rb +302 -0
  57. data/lib/kward/rpc/server.rb +76 -3
  58. data/lib/kward/rpc/session_manager.rb +43 -8
  59. data/lib/kward/rpc/transcript_normalizer.rb +14 -5
  60. data/lib/kward/sandbox/capabilities.rb +39 -0
  61. data/lib/kward/sandbox/command_runner.rb +28 -0
  62. data/lib/kward/sandbox/environment.rb +24 -0
  63. data/lib/kward/sandbox/linux_bubblewrap_runner.rb +71 -0
  64. data/lib/kward/sandbox/macos_seatbelt_runner.rb +96 -0
  65. data/lib/kward/sandbox/passthrough_runner.rb +13 -0
  66. data/lib/kward/sandbox/policy.rb +74 -0
  67. data/lib/kward/sandbox/runner_factory.rb +55 -0
  68. data/lib/kward/sandbox/unavailable_runner.rb +21 -0
  69. data/lib/kward/sandbox.rb +9 -0
  70. data/lib/kward/session_store.rb +26 -0
  71. data/lib/kward/skills/capture.rb +144 -0
  72. data/lib/kward/starter_pack_installer.rb +3 -1
  73. data/lib/kward/tab_driver.rb +87 -0
  74. data/lib/kward/tab_store.rb +74 -12
  75. data/lib/kward/tools/code_search.rb +8 -2
  76. data/lib/kward/tools/fetch_content.rb +4 -2
  77. data/lib/kward/tools/fetch_raw.rb +3 -1
  78. data/lib/kward/tools/registry.rb +56 -8
  79. data/lib/kward/tools/search/code.rb +46 -12
  80. data/lib/kward/tools/search/web.rb +60 -17
  81. data/lib/kward/tools/search/web_fetch.rb +206 -38
  82. data/lib/kward/tools/web_search.rb +3 -1
  83. data/lib/kward/update_check.rb +2 -1
  84. data/lib/kward/version.rb +1 -1
  85. data/lib/kward/workspace.rb +18 -3
  86. data/lib/kward/workspace_factory.rb +17 -0
  87. data/templates/default/fulldoc/html/js/kward.js +1 -0
  88. data/templates/default/kward_navigation.rb +5 -2
  89. data/templates/default/layout/html/layout.erb +2 -0
  90. data/templates/default/layout/html/setup.rb +2 -0
  91. metadata +22 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a18a2a0c800780596999ee897ed61afcef22c964012f2b2ed3f51a3a66239c5
4
- data.tar.gz: 83badb23b87cae5e3198e00c65f0c53acbe2e0561f00164c4e5b40aacb3d10d4
3
+ metadata.gz: 79174a2cb7441a44857a53568078c50b2c7735d7a8f7507ce6e8d1199f8b37fa
4
+ data.tar.gz: c83fda7c64aea1ad5f8af38c5ee0bb1d0c56a3c05efa3457c02fcd5b3049cb99
5
5
  SHA512:
6
- metadata.gz: 5c4bd15eb61a2b62b5165b46d393fa60608dc702b773cbb0596bdd64deed1799332f22a5b271c146142f8f1f2769111e3e0075db34626818a71c4e502a14b49d
7
- data.tar.gz: 9953137b41415eff742904f3a4f4d63a610da01351000d5b08d4191ad180bfbdff5c001315513bbf4fabd1918843a6c214712f9af737c0025c5494e6c84494f8
6
+ metadata.gz: 9088afe9fb4976a8a40ec08a0297ee99d075f9df756465f68e04482c55f5fbb1d5b0b8d5e20b880d258253d8e015ce91b745a1db57c3ce03374b912d4fc109fe
7
+ data.tar.gz: 7452c7d1674338e52b3216f648b798f9181cf421db840bc54a74270acebd40c1aa67aa1c2dbbfaea322908cd50344e34500a79cb68033bdfc1fa62642cefbf20
@@ -16,7 +16,7 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby-version: ['3.2', 'ruby']
19
+ ruby-version: ['3.4', 'ruby']
20
20
  steps:
21
21
  - name: Checkout
22
22
  uses: actions/checkout@v4
@@ -27,11 +27,16 @@ jobs:
27
27
  ruby-version: ${{ matrix.ruby-version }}
28
28
  bundler-cache: true
29
29
 
30
+ - name: Install sandbox test dependency
31
+ run: sudo apt-get update && sudo apt-get install --yes bubblewrap
32
+
30
33
  - name: Check syntax
31
34
  run: find lib test -name '*.rb' -print0 | xargs -0 ruby -c
32
35
 
33
36
  - name: Check runtime warnings
34
- run: ruby -w -Ilib -e 'require "kward"'
37
+ run: bundle exec ruby -w -Ilib -e 'require "kward"'
35
38
 
36
39
  - name: Run tests
40
+ env:
41
+ KWARD_RUN_BUBBLEWRAP_TESTS: "1"
37
42
  run: bundle exec rake test
@@ -25,7 +25,7 @@ jobs:
25
25
  - name: Set up Ruby
26
26
  uses: ruby/setup-ruby@v1
27
27
  with:
28
- ruby-version: '3.3'
28
+ ruby-version: '3.4'
29
29
  bundler-cache: true
30
30
 
31
31
  - name: Build documentation
data/CHANGELOG.md CHANGED
@@ -4,6 +4,56 @@ All notable changes to Kward will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.79.0] - 2026-07-19
8
+
9
+ ### Added
10
+
11
+ - Added a Local OpenAI-compatible model provider for Ollama, LM Studio, and llama.cpp, including model discovery, streamed tool calls, configurable context windows, CLI/RPC model selection, and a local-model setup guide.
12
+ - Added replacement system-prompt files and an option to omit global principles for smaller-model prompt budgets.
13
+ - Added skill capture from saved session branches. Review model-generated personal `SKILL.md` drafts in the CLI or Pan, or use the equivalent RPC workflow before explicitly saving them.
14
+ - Added opt-in OS-enforced sandboxing for model-requested shell commands. macOS uses Seatbelt and Linux uses Bubblewrap when available; requested sandboxing fails closed when no supported backend can enforce it. The interactive `/sandbox` command reports and updates the global policy.
15
+
16
+ ### Changed
17
+
18
+ - Clarified command-sandbox configuration, platform setup, and limits across the security, permissions, workspace-tools, RPC, and configuration guides.
19
+ - Sandboxed command workers now receive a sanitized environment with a private home and temporary directory; the macOS backend also blocks reads from common credential directories.
20
+ - Improved built-in tool guidance so agents use only tools advertised for the current turn and select code search, compacted-output retrieval, and structured clarification when appropriate.
21
+ - Raised the minimum supported Ruby version from 3.2 to 3.4.
22
+
23
+ ### Fixed
24
+
25
+ - Reject duplicate discovered tool names instead of silently replacing one MCP tool with another.
26
+ - Fixed an RPC race where follow-up input could queue instead of steering a turn immediately after it began.
27
+ - Prevented the RPC server from loading trusted Ruby plugins separately for plugin chats and workspace sessions, eliminating duplicate constant-definition warnings during startup.
28
+ - Prevented `/reload` and RPC runtime reloads from emitting duplicate constant-definition warnings for plugin-defined constants.
29
+ - Wrapped long side-by-side diff cells when editor soft wrap is enabled instead of clipping their contents.
30
+
31
+ ## [0.78.0] - 2026-07-15
32
+
33
+ ### Added
34
+
35
+ - Added opt-in transcript-observer delivery for plugin-owned tabs, including RPC plugin chats, so local integrations such as text-to-speech can receive permitted streamed replies.
36
+ - Added opt-in RPC support for plugin-owned chats, including explicit subscriptions, transcript snapshots, attachment-capable turns, event replay, and cancellation. Plugins remain disabled from this surface unless their tab type explicitly opts in.
37
+ - Added plugin-owned tab types, opened with `/tab open <plugin-tab>`, with typed tab persistence and the normal interactive composer, transcript, streaming, and image-input behavior. Plugin tabs are CLI-only in this release and own their own storage rather than Kward sessions.
38
+ - Added an opt-in permission policy for model-requested tools, with allow/ask/deny rules, read-only and workspace-write modes, write scopes, and interactive approval overlays. Permissions remain disabled by default and are not an OS sandbox.
39
+ - Added a custom-response path to permission approval overlays: choosing `Type something` denies the requested tool call and returns the entered guidance to the agent.
40
+
41
+ ### Changed
42
+
43
+ - Plugin-chat transcript RPC supports optional bounded, cursor-based pages for plugin drivers that opt in, avoiding full-history payloads for long-lived chats.
44
+ - Code search now synchronizes mutable repository refs before every read and search, reports the resolved commit, and accepts GitHub blob URLs as file inputs.
45
+ - Web and code research tools now cooperate with turn cancellation between requests, provider attempts, redirects, and repository scan files.
46
+ - Kward-owned HTTP requests now identify themselves with `User-Agent: Kward/<version>`.
47
+
48
+ ### Fixed
49
+
50
+ - Fixed `fetch_content` site navigation by preferring semantic main content over nested article cards, preserving inline and standalone link destinations, listing bounded discovered navigation links, and extracting ordered lists and simple tables.
51
+ - Prevented duplicate session-backed tabs from restoring as mirrored conversations after restart.
52
+ - Fixed `fetch_content` on documentation pages with large scripts or metadata before the main content by separating bounded page downloads from extracted output limits; plain-text extraction now parses HTML instead of returning cleaned markup.
53
+ - Fixed raw fetches so their response limit is enforced while reading the network body.
54
+ - Fixed stale code-search reads and searches by treating cached repositories as reusable local storage rather than authoritative snapshots.
55
+ - Restored GPT-5.6 Luna requests through Codex with a scoped Responses Lite compatibility workaround; normal Codex requests retain Kward's own identity.
56
+
7
57
  ## [0.77.0] - 2026-07-11
8
58
 
9
59
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kward (0.77.0)
4
+ kward (0.79.0)
5
5
  base64
6
6
  nokogiri
7
7
  tiktoken_ruby
@@ -146,7 +146,7 @@ CHECKSUMS
146
146
  html-proofer (5.2.1) sha256=fdd958a7cbf9c3255fb96fe7cfc4e611f64e2706e469488a3326309ad007d2fd
147
147
  io-event (1.16.2) sha256=9f9cb0a96ea5c3850a672606c65f27bc96d7621399ef6196acbfe2be0cd1279c
148
148
  json (2.19.9) sha256=9b9025b7cdddafa38d316eca0b2358488e42d417045c1b90d216a9fefe46b79a
149
- kward (0.77.0)
149
+ kward (0.79.0)
150
150
  logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
151
151
  metrics (0.15.0) sha256=61ded5bac95118e995b1bc9ed4a5f19bc9814928a312a85b200abbdac9039072
152
152
  minitest (6.0.6) sha256=153ea36d1d987a62942382b61075745042a2b3123b1cd48f4c3675af9cc7d6f1
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Kward
2
2
 
3
- Kward is an extendable Ruby CLI coding agent. It can chat with you about a project, inspect and edit files, run confirmed shell commands, search the web, look up public source code, save local sessions, and load trusted Ruby plugins for custom workflows.
3
+ Kward is an extendable Ruby CLI coding agent. It can chat with you about a project, inspect and edit files, run local shell commands, search the web, look up public source code, save local sessions, and load trusted Ruby plugins for custom workflows.
4
4
 
5
- It currently supports the OpenAI/ChatGPT Codex backend, Anthropic Claude Pro/Max subscription, OpenRouter, and experimental Copilot provider support.
5
+ It supports the OpenAI/ChatGPT Codex backend, Anthropic Claude Pro/Max subscription, OpenRouter, experimental Copilot provider support, and OpenAI-compatible local servers such as Ollama, LM Studio, and llama.cpp.
6
6
 
7
7
  ## Why use Kward?
8
8
 
@@ -76,6 +76,8 @@ Start here:
76
76
  - [Configuration](doc/configuration.md): config files, providers, models, web search, logging, and color output.
77
77
  - [Authentication](doc/authentication.md): OpenAI OAuth, Anthropic OAuth, OpenRouter API keys, and Copilot/GitHub setup.
78
78
  - [Security and trust](doc/security.md): local permissions, external data flow, trusted extensions, and safe work in unfamiliar repositories.
79
+ - [Permissions](doc/permissions.md): opt-in tool approval, write scopes, policy rules, and current limits.
80
+ - [Command sandboxing](doc/sandboxing.md): opt-in OS-enforced boundaries for model-requested shell commands.
79
81
  - [Troubleshooting](doc/troubleshooting.md): environment-specific install and runtime issues.
80
82
 
81
83
  Feature guides:
@@ -92,6 +94,7 @@ Feature guides:
92
94
  - [Skills](doc/skills.md): add reusable instructions that load only for matching tasks.
93
95
  - [MCP servers](doc/mcp.md): connect trusted local Model Context Protocol tool servers.
94
96
  - [Pan mode](doc/pan.md): use the mobile-friendly browser interface on a trusted local network.
97
+ - [Local models](doc/local-models.md): connect Ollama, LM Studio, or llama.cpp and use a minimal replacement prompt.
95
98
 
96
99
  Advanced:
97
100
 
data/doc/agent-tools.md CHANGED
@@ -38,7 +38,7 @@ This lets the assistant reason from focused evidence while preserving access to
38
38
 
39
39
  ## How tools are exposed
40
40
 
41
- `Kward::ToolRegistry` builds the available tool objects and the schemas advertised to the model. Some tools are always available in normal CLI/RPC sessions, while others depend on configuration or frontend capability:
41
+ `Kward::ToolRegistry` builds the available tool objects and the schemas advertised to the model. Kward instructs models to call only tools advertised for the current turn; a restricted RPC turn therefore receives schemas only for its selected set. Some tools are always available in normal CLI/RPC sessions, while others depend on configuration or frontend capability:
42
42
 
43
43
  - web tools can be hidden with web search configuration,
44
44
  - `read_skill` is advertised only when skills are available,
data/doc/code-search.md CHANGED
@@ -85,9 +85,9 @@ The tool uses an `action` parameter:
85
85
  | --- | --- |
86
86
  | `package_search` | find package metadata and likely source repositories. |
87
87
  | `github_search` | search public GitHub repositories. |
88
- | `repo_clone` | clone a GitHub repository into cache. |
89
- | `repo_search` | search files in a cached repository. |
90
- | `repo_read` | read a bounded line range from a cached file. |
88
+ | `repo_clone` | prewarm the local Git repository store. |
89
+ | `repo_search` | synchronize and search files in a repository. |
90
+ | `repo_read` | synchronize and read a bounded line range from a file. |
91
91
  | `list_cache` | show cached repositories. |
92
92
  | `refresh_cache` | fetch updates for a cached repository. |
93
93
  | `clear_cache` | remove a cached repository. |
@@ -99,13 +99,16 @@ The tool uses an `action` parameter:
99
99
  | `package_search` | `ecosystem`, `package` | — |
100
100
  | `github_search` | `query` | `ecosystem`, `max_results` |
101
101
  | `repo_clone` | `repo` | — |
102
- | `repo_search` | `repo`, `query` | `max_results`, `context_lines` |
103
- | `repo_read` | `repo`, `path` | `start_line`, `line_count` |
102
+ | `repo_search` | `repo`, `query` | `ref`, `max_results`, `context_lines` |
103
+ | `repo_read` | `repo` | `path`, `ref`, `start_line`, `line_count` |
104
104
  | `list_cache` | — | — |
105
105
  | `refresh_cache` | `repo` | — |
106
106
  | `clear_cache` | `repo` | — |
107
107
 
108
- - `repo` is a GitHub URL or `owner/name`.
108
+ - `repo` is a GitHub URL or `owner/name`. A GitHub `blob` URL can supply the file path and ref for `repo_read`.
109
+ - `ref` selects a branch, tag, or commit. Mutable refs are fetched before every read or search; without `ref`, Kward synchronizes the remote default branch.
110
+ - Successful reads and searches report the exact commit revision used. The local Git store reduces repeated downloads but is never silently treated as current source.
111
+ - If synchronization fails, Kward returns an error instead of silently answering from stale files.
109
112
  - `query` is a plain-text search string (not regex). Matching is case-sensitive substring.
110
113
  - `start_line` is 1-indexed.
111
114
  - `context_lines` controls how many lines before and after a match are included in search snippets.
data/doc/configuration.md CHANGED
@@ -15,6 +15,7 @@ If `KWARD_CONFIG_PATH` is set, Kward uses that file and treats its directory as
15
15
  | Change editor, diff, overlay, or session UI behavior | `/settings` → Interface |
16
16
  | Enable memory | `/settings` → Memory |
17
17
  | Configure web search or trust project skills | `/settings` → Tools & Search |
18
+ | Contain model-requested shell commands | `/sandbox` for mode and child-network access; edit config for additional writable roots |
18
19
  | Tune compaction | `/settings` → Context & Compaction |
19
20
  | Configure personas | `/settings` → Personalization; see [Personas](personas.md) |
20
21
  | Add MCP servers, lifecycle hooks, or environment-specific paths | Edit `config.json` directly |
@@ -161,6 +162,7 @@ Supported values are:
161
162
  - `anthropic` for Anthropic Claude Pro/Max subscription support.
162
163
  - `openrouter` for OpenRouter.
163
164
  - `copilot` for experimental Copilot provider support.
165
+ - `local` for an OpenAI-compatible Ollama, LM Studio, or llama.cpp server. See [Local models](local-models.md).
164
166
 
165
167
  Model settings:
166
168
 
@@ -171,6 +173,7 @@ Model settings:
171
173
  "openrouter_model": "openai/gpt-5.6-sol",
172
174
  "anthropic_model": "claude-sonnet-5",
173
175
  "copilot_model": "gpt-5-mini",
176
+ "local_model": "qwen2.5-coder:7b",
174
177
  "reasoning_effort": "medium",
175
178
  "openai_reasoning_effort": "medium",
176
179
  "openrouter_reasoning_effort": "medium",
@@ -184,6 +187,8 @@ Model settings:
184
187
 
185
188
  Set `codex_show_raw_reasoning` to `true` to display raw Codex `reasoning_text` when the API does not provide reasoning summary text. It defaults to `false`; raw reasoning can include internal or unstable model output, so enable it only when you explicitly want to inspect that stream.
186
189
 
190
+ `stream_idle_timeout_seconds` limits how long a streamed Codex, Anthropic, or Local response may go without receiving data. It defaults to `120`; set a positive value to override it. When the provider is silent longer than this limit, Kward closes the request and applies its normal transient-network retry behavior.
191
+
187
192
  Defaults:
188
193
 
189
194
  - OpenAI/Codex: `gpt-5.6-sol`
@@ -196,6 +201,24 @@ The Anthropic model choices include `claude-fable-5`, but Fable availability dep
196
201
 
197
202
  The interactive `/model` picker reads cached OpenRouter models when available. Run `kward openrouter refresh` to fetch text-capable models available to the configured OpenRouter API key and cache them under `~/.kward/cache/openrouter_models.json`. Run `kward openrouter list` to inspect the cached model ids.
198
203
 
204
+ ### Local model server
205
+
206
+ The `local` provider uses OpenAI-compatible Chat Completions and model-list endpoints. Configure a running local server with a model id and its actual context window:
207
+
208
+ ```json
209
+ {
210
+ "provider": "local",
211
+ "local_backend": "ollama",
212
+ "local_base_url": "http://127.0.0.1:11434/v1",
213
+ "local_model": "qwen2.5-coder:7b",
214
+ "local_context_window": 32768
215
+ }
216
+ ```
217
+
218
+ `local_backend` selects a convenience default: `ollama`, `lm_studio`, or `llama_cpp`. Their default base URLs are `http://127.0.0.1:11434/v1`, `http://127.0.0.1:1234/v1`, and `http://127.0.0.1:8080/v1`, respectively. Set `local_base_url` to use a custom endpoint. `local_api_key` is optional and is sent as a bearer token only when configured.
219
+
220
+ Set `local_context_window` to the context length configured for the loaded model. Kward does not infer this safely from an arbitrary local model name; without it, automatic context budgeting cannot report a reliable limit. Local providers do not expose Kward reasoning or image controls by default.
221
+
199
222
  ## Environment overrides
200
223
 
201
224
  Use environment variables for one-off runs or local secrets that you do not want in config.
@@ -207,6 +230,11 @@ Provider and model:
207
230
  - `OPENAI_REASONING_EFFORT`
208
231
  - `OPENROUTER_MODEL`
209
232
  - `OPENROUTER_REASONING_EFFORT`
233
+ - `KWARD_LOCAL_BACKEND`
234
+ - `KWARD_LOCAL_BASE_URL`
235
+ - `KWARD_LOCAL_MODEL`
236
+ - `KWARD_LOCAL_CONTEXT_WINDOW`
237
+ - `KWARD_LOCAL_API_KEY`
210
238
  - `ANTHROPIC_MODEL`
211
239
  - `ANTHROPIC_REASONING_EFFORT`
212
240
  - `COPILOT_MODEL`
@@ -500,6 +528,31 @@ Do not put shared or published API keys in this file.
500
528
 
501
529
  Put global engineering principles in `PRINCIPLES.md` beside your config file, usually `~/.kward/PRINCIPLES.md`. Kward appends this file to its built-in system instructions when present. Existing config-directory `AGENTS.md` files are still read as a legacy alias when `PRINCIPLES.md` is absent.
502
530
 
531
+ ## Replacement system prompt
532
+
533
+ Set `system_prompt.file` to use a file as the entire system prompt. In replacement mode Kward does not append its built-in instructions, global principles, memory context, personas, plugin context, skills, or workspace `AGENTS.md` guidance.
534
+
535
+ ```json
536
+ {
537
+ "system_prompt": {
538
+ "file": "prompts/local-minimal.md",
539
+ "include_principles": false
540
+ }
541
+ }
542
+ ```
543
+
544
+ Relative paths are resolved beside `config.json`. The file is sent to the configured model and can be recorded in session prompt snapshots, so do not place secrets in it. Use `kward sysprompt` to inspect the exact active prompt.
545
+
546
+ To retain Kward's normal prompt while omitting only global `PRINCIPLES.md` (and its legacy config-directory `AGENTS.md` fallback), configure:
547
+
548
+ ```json
549
+ {
550
+ "system_prompt": {
551
+ "include_principles": false
552
+ }
553
+ }
554
+ ```
555
+
503
556
  ## Workspace AGENTS.md
504
557
 
505
558
  By default, Kward does not inject the full workspace `AGENTS.md` into every request. When a workspace `AGENTS.md` exists, Kward injects a compact instruction telling the model to read it for repository-related tasks before analyzing or modifying project files.
@@ -526,7 +579,59 @@ Workspace guardrails are enabled by default. File tools such as `read_file`, `wr
526
579
  }
527
580
  ```
528
581
 
529
- This is not a sandbox setting. Shell commands already run as your OS user from the workspace directory and can access anything that user can access.
582
+ This is not a sandbox setting. File guardrails constrain Kward file tools, not arbitrary shell commands. See [Command sandboxing](sandboxing.md) to apply an opt-in operating-system boundary to model-requested `run_shell_command` workers.
583
+
584
+ ## Command sandboxing
585
+
586
+ Sandboxing is off by default. Use `/sandbox` to inspect or change the mode and child-network access. For additional writable roots or Git metadata protection, edit the `sandbox` config directly. `sandbox.mode` accepts `off`, `read_only`, or `workspace_write`; `sandbox.network` defaults to `deny`, and `sandbox.protect_git_metadata` defaults to `true`.
587
+
588
+ ```json
589
+ {
590
+ "sandbox": {
591
+ "mode": "workspace_write",
592
+ "network": "deny"
593
+ }
594
+ }
595
+ ```
596
+
597
+ When Kward cannot enforce a requested non-off mode, it denies the command rather than running it unrestricted. Current support and limits are documented in [Command sandboxing](sandboxing.md).
598
+
599
+ ## Permissions
600
+
601
+ Permissions are off by default. When enabled, Kward evaluates model-requested tools before execution. This is a permission policy, not an operating-system sandbox: permitted shell commands still run with your user account's access.
602
+
603
+ ```json
604
+ {
605
+ "permissions": {
606
+ "enabled": true,
607
+ "mode": "ask"
608
+ }
609
+ }
610
+ ```
611
+
612
+ Available modes are:
613
+
614
+ | Mode | Behavior |
615
+ | --- | --- |
616
+ | `ask` | Read-only tools run normally; file changes, shell commands, web tools, and MCP tools need approval. |
617
+ | `workspace-write` | File changes within `write_scopes` run without approval; shell and network tools still need approval. |
618
+ | `read-only` | Denies file changes, shell commands, web tools, and MCP tools. |
619
+ | `deny-by-default` | Denies risky tools unless an `allow` rule matches. |
620
+
621
+ `allow`, `ask`, and `deny` rules are arrays of objects matching `tool`, `path`, `host`, `command`, or `source`. Deny rules always take precedence, then ask, then allow. Use `write_scopes` to restrict writes in `workspace-write` mode:
622
+
623
+ ```json
624
+ {
625
+ "permissions": {
626
+ "enabled": true,
627
+ "mode": "workspace-write",
628
+ "write_scopes": ["lib/**", "test/**"],
629
+ "deny": [{ "tool": "run_shell_command", "command": "git push*" }]
630
+ }
631
+ }
632
+ ```
633
+
634
+ The interactive CLI presents an approval overlay for an `ask` decision. RPC clients can use their existing `approvalMode: "ask"` bridge. Frontends without an approval bridge, including Pan, fail closed for policy approvals.
530
635
 
531
636
  ## Logging and stats
532
637
 
data/doc/extensibility.md CHANGED
@@ -43,6 +43,8 @@ If `KWARD_CONFIG_PATH` is set, `PRINCIPLES.md` lives beside that config file.
43
43
 
44
44
  If `PRINCIPLES.md` is absent, Kward also reads `~/.kward/AGENTS.md` (or the equivalent beside a custom config path) as a legacy alias. New setups should use `PRINCIPLES.md`. See [Configuration](configuration.md) for details.
45
45
 
46
+ For a small local model, set `system_prompt.include_principles` to `false` to keep Kward's normal prompt without global principles. Set `system_prompt.file` only when you want the file to replace the entire assembled system prompt; replacement mode also omits personas, skills, memory, plugins, and workspace guidance. See [Local models](local-models.md) for a complete setup.
47
+
46
48
  ## Project instructions: `AGENTS.md`
47
49
 
48
50
  Put repository-specific rules in the workspace root:
@@ -6,7 +6,7 @@ This page gets you from install to a first useful chat.
6
6
 
7
7
  ## Requirements
8
8
 
9
- - Ruby 3.2 or newer.
9
+ - Ruby 3.4 or newer.
10
10
  - Credentials for one model provider. The easiest setup is `kward login` or `/login` inside Kward.
11
11
  - Bundler only if you run Kward from a source checkout.
12
12
 
@@ -0,0 +1,130 @@
1
+ # Local models
2
+
3
+ Kward can connect to a local model server that provides OpenAI-compatible Chat Completions. This is useful when you want offline development, control over model selection, or a smaller prompt for a local coding model.
4
+
5
+ Kward connects to an already-running server. It does not install runtimes, download models, choose GPU settings, or load models for you.
6
+
7
+ ## Choose and start a runtime
8
+
9
+ Use one of these local servers:
10
+
11
+ | Runtime | Default Kward base URL |
12
+ | --- | --- |
13
+ | Ollama | `http://127.0.0.1:11434/v1` |
14
+ | LM Studio | `http://127.0.0.1:1234/v1` |
15
+ | llama.cpp `llama-server` | `http://127.0.0.1:8080/v1` |
16
+
17
+ Start the server and load a chat model before starting Kward. Then confirm that it reports models:
18
+
19
+ ```bash
20
+ curl http://127.0.0.1:11434/v1/models
21
+ ```
22
+
23
+ Use the equivalent configured port for LM Studio or llama.cpp.
24
+
25
+ ## Configure Kward
26
+
27
+ Add a Local provider configuration to `~/.kward/config.json`:
28
+
29
+ ```json
30
+ {
31
+ "provider": "local",
32
+ "local_backend": "ollama",
33
+ "local_model": "qwen2.5-coder:7b",
34
+ "local_context_window": 32768
35
+ }
36
+ ```
37
+
38
+ `local_backend` supplies a default endpoint for `ollama`, `lm_studio`, or `llama_cpp`. Set `local_base_url` when the server uses another host, port, path, Docker address, reverse proxy, or TLS endpoint:
39
+
40
+ ```json
41
+ {
42
+ "provider": "local",
43
+ "local_base_url": "http://127.0.0.1:1234/v1",
44
+ "local_model": "loaded-model-id",
45
+ "local_context_window": 32768
46
+ }
47
+ ```
48
+
49
+ Set `local_context_window` to the context length actually configured for the loaded model. Kward cannot reliably infer it from a local model name. The value lets Kward report meaningful context usage and make safe auto-compaction decisions.
50
+
51
+ If your local proxy requires a token, set `local_api_key` or `KWARD_LOCAL_API_KEY`. Kward sends it as a bearer token only for Local requests.
52
+
53
+ You can also choose **Local** from `/settings` → **Model & Reasoning** → **Provider**, then select a model with `/model`.
54
+
55
+ ## Use a minimal replacement prompt
56
+
57
+ Smaller models often work better with a short, direct prompt. Create a file beside your Kward config, for example `~/.kward/prompts/local-minimal.md`:
58
+
59
+ ```markdown
60
+ You are a coding assistant.
61
+ Use the provided tools when needed.
62
+ Inspect relevant files before changing them.
63
+ Make only requested changes and report what changed.
64
+ ```
65
+
66
+ Configure it as Kward's replacement system prompt:
67
+
68
+ ```json
69
+ {
70
+ "system_prompt": {
71
+ "file": "prompts/local-minimal.md",
72
+ "include_principles": false
73
+ }
74
+ }
75
+ ```
76
+
77
+ This file is the entire system prompt. Kward does not add its built-in instructions, `PRINCIPLES.md`, memory context, personas, plugin context, skills, or workspace `AGENTS.md` guidance in replacement mode.
78
+
79
+ If you want Kward's normal prompt but do not want global principles sent on every turn, omit the `file` and disable only principles:
80
+
81
+ ```json
82
+ {
83
+ "system_prompt": {
84
+ "include_principles": false
85
+ }
86
+ }
87
+ ```
88
+
89
+ Check the exact result before relying on it:
90
+
91
+ ```bash
92
+ kward sysprompt
93
+ kward sysprompt --raw
94
+ ```
95
+
96
+ Do not put secrets in a replacement prompt. Its contents are sent to the model and may be stored as a session prompt snapshot.
97
+
98
+ ## Verify tool calling
99
+
100
+ A coding agent needs more than ordinary chat: the model must request tools with valid arguments and use their results. Start with a safe read-only task:
101
+
102
+ ```text
103
+ Read README.md and summarize the project's test command. Do not modify files.
104
+ ```
105
+
106
+ Choose a model trained for tool or function calling. If it responds with prose instead of tool calls, use a tool-capable model or make the replacement prompt's tool guidance more explicit.
107
+
108
+ ## Security and limits
109
+
110
+ The default endpoints use loopback addresses. If you configure another host, Kward can send prompts, workspace-derived content, attachments, and tool results over that connection. Use TLS and authentication for any endpoint outside your machine or trusted private network.
111
+
112
+ Local model support uses the OpenAI-compatible Chat Completions interface, including streaming text and function/tool calls. Kward does not promise reasoning controls or image support for arbitrary local models.
113
+
114
+ ## Troubleshooting
115
+
116
+ **No models appear in `/model`**
117
+
118
+ Confirm the server is running, a model is loaded, and `GET /v1/models` succeeds. You can still set `local_model` manually when discovery is unavailable.
119
+
120
+ **The model stops early or Kward compacts too soon**
121
+
122
+ Check `local_context_window`. It must match the server's loaded-model context setting, not just the model's advertised training context.
123
+
124
+ **Tool calls are malformed or missing**
125
+
126
+ Use a tool-trained model and a compatible chat template. Test with a read-only task before allowing writes or shell commands.
127
+
128
+ **The server is slow**
129
+
130
+ Reduce the model size, reduce context length, verify GPU acceleration in the local runtime, or raise `stream_idle_timeout_seconds` if the server has long silent intervals.