kward 0.78.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 (61) 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 +24 -0
  5. data/Gemfile.lock +2 -2
  6. data/README.md +4 -2
  7. data/doc/agent-tools.md +1 -1
  8. data/doc/configuration.md +68 -2
  9. data/doc/extensibility.md +2 -0
  10. data/doc/getting-started.md +1 -1
  11. data/doc/local-models.md +130 -0
  12. data/doc/permissions.md +3 -2
  13. data/doc/releasing.md +1 -1
  14. data/doc/rpc.md +12 -1
  15. data/doc/sandboxing.md +120 -0
  16. data/doc/security.md +11 -5
  17. data/doc/skills.md +10 -0
  18. data/doc/workspace-tools.md +3 -3
  19. data/kward.gemspec +1 -1
  20. data/lib/kward/cli/doctor.rb +21 -0
  21. data/lib/kward/cli/runtime_helpers.rb +1 -1
  22. data/lib/kward/cli/settings.rb +66 -4
  23. data/lib/kward/cli/slash_commands.rb +109 -1
  24. data/lib/kward/cli.rb +2 -1
  25. data/lib/kward/config_files.rb +80 -1
  26. data/lib/kward/conversation.rb +14 -1
  27. data/lib/kward/local_command_runner.rb +2 -2
  28. data/lib/kward/model/client.rb +140 -4
  29. data/lib/kward/model/model_info.rb +11 -1
  30. data/lib/kward/model/payloads.rb +1 -0
  31. data/lib/kward/model/stream_parser.rb +58 -26
  32. data/lib/kward/pan/index.html.erb +50 -0
  33. data/lib/kward/pan/server.rb +49 -2
  34. data/lib/kward/plugin_registry.rb +1 -1
  35. data/lib/kward/prompt_interface/editor/controller.rb +36 -3
  36. data/lib/kward/prompt_interface.rb +18 -0
  37. data/lib/kward/prompts/commands.rb +2 -0
  38. data/lib/kward/prompts.rb +16 -5
  39. data/lib/kward/rpc/plugin_chat_manager.rb +4 -1
  40. data/lib/kward/rpc/server.rb +42 -4
  41. data/lib/kward/rpc/session_manager.rb +42 -8
  42. data/lib/kward/sandbox/capabilities.rb +39 -0
  43. data/lib/kward/sandbox/command_runner.rb +28 -0
  44. data/lib/kward/sandbox/environment.rb +24 -0
  45. data/lib/kward/sandbox/linux_bubblewrap_runner.rb +71 -0
  46. data/lib/kward/sandbox/macos_seatbelt_runner.rb +96 -0
  47. data/lib/kward/sandbox/passthrough_runner.rb +13 -0
  48. data/lib/kward/sandbox/policy.rb +74 -0
  49. data/lib/kward/sandbox/runner_factory.rb +55 -0
  50. data/lib/kward/sandbox/unavailable_runner.rb +21 -0
  51. data/lib/kward/sandbox.rb +9 -0
  52. data/lib/kward/session_store.rb +26 -0
  53. data/lib/kward/skills/capture.rb +144 -0
  54. data/lib/kward/tools/registry.rb +19 -4
  55. data/lib/kward/version.rb +1 -1
  56. data/lib/kward/workspace.rb +18 -3
  57. data/lib/kward/workspace_factory.rb +17 -0
  58. data/templates/default/fulldoc/html/js/kward.js +1 -0
  59. data/templates/default/kward_navigation.rb +4 -2
  60. data/templates/default/layout/html/setup.rb +1 -0
  61. metadata +16 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e77436e5f94e314fcab35e347c16994eb8f92f990ad4c3ebdc6ab76a393cb1b4
4
- data.tar.gz: 50b73b48c76c737d5b7d2534380547d94e357cac6dec4528a80cfe36ea8f6bdf
3
+ metadata.gz: 79174a2cb7441a44857a53568078c50b2c7735d7a8f7507ce6e8d1199f8b37fa
4
+ data.tar.gz: c83fda7c64aea1ad5f8af38c5ee0bb1d0c56a3c05efa3457c02fcd5b3049cb99
5
5
  SHA512:
6
- metadata.gz: bc17d7227fa1910ee107b840ec138ee19c8ed905d137d7aeed3fc552e2ec6d3aca1fb3d8df4febce7c7e84380a7e4f4378c3177415b3ab7a59fb22d344b92d2c
7
- data.tar.gz: 56521cdb264f5745f2023a010892b99ec91693f4444c17c0f1aa7b9375e9d0727ba7c9ce280d4e0af9141ae5466073393fbf9d112d53bf7ea12872aa68c7f617
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,30 @@ 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
+
7
31
  ## [0.78.0] - 2026-07-15
8
32
 
9
33
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kward (0.78.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.78.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
 
@@ -77,6 +77,7 @@ Start here:
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
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.
80
81
  - [Troubleshooting](doc/troubleshooting.md): environment-specific install and runtime issues.
81
82
 
82
83
  Feature guides:
@@ -93,6 +94,7 @@ Feature guides:
93
94
  - [Skills](doc/skills.md): add reusable instructions that load only for matching tasks.
94
95
  - [MCP servers](doc/mcp.md): connect trusted local Model Context Protocol tool servers.
95
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.
96
98
 
97
99
  Advanced:
98
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/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,7 +187,7 @@ 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
 
187
- `stream_idle_timeout_seconds` limits how long a streamed Codex or Anthropic 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.
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.
188
191
 
189
192
  Defaults:
190
193
 
@@ -198,6 +201,24 @@ The Anthropic model choices include `claude-fable-5`, but Fable availability dep
198
201
 
199
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.
200
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
+
201
222
  ## Environment overrides
202
223
 
203
224
  Use environment variables for one-off runs or local secrets that you do not want in config.
@@ -209,6 +230,11 @@ Provider and model:
209
230
  - `OPENAI_REASONING_EFFORT`
210
231
  - `OPENROUTER_MODEL`
211
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`
212
238
  - `ANTHROPIC_MODEL`
213
239
  - `ANTHROPIC_REASONING_EFFORT`
214
240
  - `COPILOT_MODEL`
@@ -502,6 +528,31 @@ Do not put shared or published API keys in this file.
502
528
 
503
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.
504
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
+
505
556
  ## Workspace AGENTS.md
506
557
 
507
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.
@@ -528,7 +579,22 @@ Workspace guardrails are enabled by default. File tools such as `read_file`, `wr
528
579
  }
529
580
  ```
530
581
 
531
- 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).
532
598
 
533
599
  ## Permissions
534
600
 
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.
data/doc/permissions.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Kward's permission policy lets you put a human decision between a model-requested tool call and its side effect. It is useful when you want the agent to inspect a project freely, but want to confirm edits, commands, web requests, or MCP calls as they arise.
4
4
 
5
- Permissions are **off by default**. Enabling them does not sandbox Kward or its subprocesses: an allowed shell command still runs with your operating-system user permissions.
5
+ Permissions are **off by default**. Enabling them does not sandbox Kward or its subprocesses: an allowed shell command still runs with your operating-system user permissions unless you separately enable [command sandboxing](sandboxing.md) for model-requested shell commands.
6
6
 
7
7
  ## Start with approval mode
8
8
 
@@ -169,11 +169,12 @@ The policy runs before Kward dispatches a model-requested tool. It does not cons
169
169
  - direct commands that you type yourself—`!command`, `/shell`, and `/pty`—are treated as your actions and are outside this first policy scope;
170
170
  - plugins, hooks, and MCP servers are trusted local extensions with their own process access.
171
171
 
172
- For sensitive work, use a restricted operating-system account, container, virtual machine, or disposable checkout. A future OS-enforced sandbox may provide stronger filesystem and network isolation; it is not part of the current permissions feature.
172
+ For sensitive work, use a restricted operating-system account, container, virtual machine, or disposable checkout. [Command sandboxing](sandboxing.md) is a separate, opt-in operating-system boundary for model-requested `run_shell_command` workers. It can add filesystem and child-network restrictions, but does not cover Kward's host process, extensions, or direct interactive commands.
173
173
 
174
174
  ## Related guides
175
175
 
176
176
  - [Security and trust](security.md): trust boundaries, extensions, and safe work in unfamiliar repositories.
177
177
  - [Configuration](configuration.md#Permissions): the complete configuration reference.
178
+ - [Command sandboxing](sandboxing.md): configure the separate OS boundary for model-requested shell commands.
178
179
  - [Lifecycle hooks](lifecycle-hooks.md): add trusted local policy or automation around Kward events.
179
180
  - [RPC protocol](rpc.md#Tool_approval_bridge): implement the approval bridge in an RPC client.
data/doc/releasing.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Releasing Kward
2
2
 
3
- Kward requires Ruby >= 3.2 (`spec.required_ruby_version` in `kward.gemspec`). If you develop with a newer Ruby, verify tests pass against the minimum supported version before releasing.
3
+ Kward requires Ruby >= 3.4 (`spec.required_ruby_version` in `kward.gemspec`). If you develop with a newer Ruby, verify tests pass against the minimum supported version before releasing.
4
4
 
5
5
  Release steps before publishing:
6
6
 
data/doc/rpc.md CHANGED
@@ -62,11 +62,12 @@ Detailed capability fields include:
62
62
  - `auth`: Kward auth provider format, OpenAI and Anthropic OAuth, OpenRouter API-key login, GitHub/Copilot status reporting, and provider logout for stored credentials. GitHub OAuth login is CLI-only; RPC reports `supported: false` for the GitHub provider with a reason string.
63
63
  - `memory`: opt-in structured memory support, interactive prompt injection only, JSON/JSONL local storage, and dedicated `memory/*` methods.
64
64
  - `commands`: supported `commands/list` capability for prompt, skill, and plugin command sources, plus plugin execution through `commands/run` or plugin slash turns.
65
+ - `skillCapture`: capture a reviewed personal `SKILL.md` from any saved session’s active branch through `skills/captureSessions`, `skills/captureDraft`, and `skills/saveCapturedDraft`.
65
66
  - `mcp`: local stdio MCP server support through the shared `mcpServers` config. RPC exposes MCP tools to turns and advertises discovery with `methods: ["tools/list", "mcp/status"]`, `toolMetadata: true`, and `serverStatus: true`. MCP resources, prompts, sampling, and Streamable HTTP are explicitly unsupported for now.
66
67
  - `startupResources`: supported startup resource listing for context, skills, prompts, and plugins.
67
68
  - `extensionUi`: question bridge support via `ui/question` and `ui/answerQuestion`, plus plugin footer updates via `ui/footer`; other UI primitives are explicitly unsupported.
68
69
  - `composer`: composer-only UI features. Interactive session diff totals are explicitly unsupported over RPC (`composer.sessionDiff.supported: false`) because RPC clients already receive per-tool diff results and no live composer status payload is exposed. Clipboard copy is also unsupported over RPC (`composer.copy.supported: false`) because UI clients own clipboard access.
69
- - `security`: trusted-local behavior with optional per-turn tool approval. By default there is no workspace mutation guard or tool approval and shell/file mutation can run. File-tool workspace guardrails are reported under `capabilities.events.tools.workspaceGuardrails` and `runtime/state.workspaceGuardrailsEnabled`.
70
+ - `security`: trusted-local behavior with optional per-turn tool approval. By default there is no workspace mutation guard or tool approval and shell/file mutation can run. File-tool workspace guardrails are reported under `capabilities.events.tools.workspaceGuardrails` and `runtime/state.workspaceGuardrailsEnabled`. `security.sandbox` reports the configured command-worker sandbox mode, enforcement backend, filesystem/network capability, and explicitly unsupported session pinning and one-time elevation. See [Command sandboxing](sandboxing.md) for its scope and limits.
70
71
  - `export`: supported transcript export formats. Currently `markdown` and `html`; default is `markdown`.
71
72
  - `starterPack`: explicitly unsupported (`supported: false`, reason `cliOnlyInstallCommand`). Use `kward init` from the shell.
72
73
  - `shell`: explicitly unsupported (`supported: false`, reason `interactiveTuiOnly`) because `/shell` is the local embedded TUI shell.
@@ -745,6 +746,16 @@ Params:
745
746
 
746
747
  Returns frontend-neutral slash command metadata for configured prompt templates, skills, and plugins. Prompt command names omit the leading slash. Skill command names use `skill:<name>`. Plugin command names omit the leading slash and include `executable: true`. Builtin terminal-only commands are omitted. Prompt commands can be submitted directly to `turns/start` as slash commands or expanded first with `prompts/expand`; plugin commands can be submitted to `turns/start` or run explicitly with `commands/run`.
747
748
 
749
+ ### `skills/captureSessions`, `skills/captureDraft`, and `skills/saveCapturedDraft`
750
+
751
+ Use this two-step workflow to capture a personal skill from a saved session:
752
+
753
+ 1. Call `skills/captureSessions` to list available persisted session sources.
754
+ 2. Call `skills/captureDraft` with `sessionPath`. Kward sends the selected active branch, including available raw tool output, to the active model provider and returns an editable `SKILL.md` draft. It rejects a source that exceeds the active model context rather than truncating it.
755
+ 3. Review and edit `content`, then call `skills/saveCapturedDraft`. Set `overwrite: true` only after explicitly confirming replacement of an existing personal skill.
756
+
757
+ Captured skills are saved under the Kward config directory, are not activated automatically, and no file is written until the final save call succeeds.
758
+
748
759
  ### `resources/startup`
749
760
 
750
761
  Params:
data/doc/sandboxing.md ADDED
@@ -0,0 +1,120 @@
1
+ # Command sandboxing
2
+
3
+ Kward can optionally apply an operating-system sandbox to model-requested
4
+ `run_shell_command` calls. The sandbox is a technical boundary for the command
5
+ and every process it starts; it is separate from Kward's [permission
6
+ policy](permissions.md), which decides whether Kward should start a tool at all.
7
+
8
+ Sandboxing is **off by default**. When you request a non-off mode and Kward
9
+ cannot enforce it on the current platform, the command is denied rather than
10
+ run without the requested boundary.
11
+
12
+ ## Configure a command sandbox
13
+
14
+ Add a `sandbox` section to your user config, normally `~/.kward/config.json`:
15
+
16
+ ```json
17
+ {
18
+ "sandbox": {
19
+ "mode": "workspace_write",
20
+ "network": "deny",
21
+ "writable_roots": [],
22
+ "protect_git_metadata": true
23
+ }
24
+ }
25
+ ```
26
+
27
+ Available modes are:
28
+
29
+ | Mode | Command filesystem writes |
30
+ | --- | --- |
31
+ | `off` | Existing unrestricted command behavior. |
32
+ | `read_only` | Workspace writes are denied. Kward gives the command a private temporary directory for command-local scratch files. |
33
+ | `workspace_write` | Writes are allowed in the active workspace and the private command temporary directory. |
34
+
35
+ `writable_roots` lets you grant additional, existing host paths to commands in
36
+ `workspace_write` mode—for example, a known local build cache. Configure these
37
+ paths only in your user config. Do not add a path merely because a repository
38
+ instruction or model response asks for it. `protect_git_metadata` defaults to
39
+ `true`; this prevents sandboxed commands from changing `.git`, including
40
+ staging and committing changes.
41
+
42
+ `network` controls child-process network access:
43
+
44
+ | Value | Child-process network access |
45
+ | --- | --- |
46
+ | `deny` | Denied by the operating-system backend. This is the default. |
47
+ | `allow` | Allowed with the same network reachability as your user account. |
48
+
49
+ ## Interactive controls
50
+
51
+ Use `/sandbox` in the terminal UI to inspect or update the global policy:
52
+
53
+ ```text
54
+ /sandbox status
55
+ /sandbox read_only
56
+ /sandbox workspace_write
57
+ /sandbox off
58
+ /sandbox network deny
59
+ /sandbox network allow
60
+ ```
61
+
62
+ Changes apply to newly created sessions and tabs. Existing turns keep the
63
+ workspace and command runner they started with, so start a new session or tab
64
+ after changing the mode.
65
+
66
+ ## Platform support
67
+
68
+ | Platform | Backend | Status |
69
+ | --- | --- | --- |
70
+ | macOS | Seatbelt through `/usr/bin/sandbox-exec` | Supported for command workers. Kward checks availability at runtime. |
71
+ | Linux | Bubblewrap | Supported when `bwrap` can create the required namespaces. |
72
+ | Windows | None | Unsupported. A requested non-off policy fails closed. |
73
+
74
+ On Debian or Ubuntu, install Bubblewrap with `sudo apt install bubblewrap`; on
75
+ Fedora, use `sudo dnf install bubblewrap`. A present `bwrap` executable can
76
+ still be prevented from creating namespaces by host policy. In that case,
77
+ Kward fails the command closed instead of running it unrestricted.
78
+
79
+ The macOS `sandbox-exec` utility is deprecated by Apple. Kward therefore treats
80
+ it as a capability-detected backend and verifies enforcement with platform
81
+ integration tests. It is not a promise that future macOS releases will retain
82
+ this interface.
83
+
84
+ ## Boundaries and limits
85
+
86
+ The current implementation protects **model-requested command workers only**.
87
+ It does not sandbox:
88
+
89
+ - the Kward Ruby host process;
90
+ - model-provider, search-provider, or RPC traffic;
91
+ - trusted Ruby plugins;
92
+ - MCP servers, lifecycle hooks, `/shell`, `!command`, or `/pty`.
93
+
94
+ Sandboxed command workers receive a minimal environment: Kward preserves only
95
+ basic terminal, locale, and path variables, then supplies a private `HOME` and
96
+ temporary directory. Credentials and runtime-injection variables are not
97
+ inherited. On macOS, Seatbelt also denies reads from common credential locations
98
+ under the host home directory, including `.kward`, `.ssh`, `.aws`, `.gnupg`, and
99
+ selected cloud/CLI configuration directories.
100
+
101
+ This is defense in depth, not complete secret-file read isolation: commands
102
+ still receive system and development-tool reads needed for normal local work.
103
+ On Linux, Bubblewrap provides a read-only view of the host filesystem outside
104
+ its explicitly writable paths; it does not hide every file your account can
105
+ read. For sensitive repositories, use a disposable checkout, VM, or container
106
+ in addition to Kward's command sandbox.
107
+
108
+ The RPC `initialize.capabilities.security.sandbox` payload reports the active
109
+ mode, backend, and whether filesystem and child-network enforcement are active.
110
+ It also reports unsupported features, including session pinning and one-time
111
+ sandbox elevation; those are not available yet.
112
+
113
+ ## Related guides
114
+
115
+ - [Security and trust](security.md) explains Kward's broader trust boundaries.
116
+ - [Permissions](permissions.md) controls whether Kward starts a model-requested
117
+ tool; it does not constrain a command after it starts.
118
+ - [Configuration](configuration.md#Command_sandboxing) covers the full config
119
+ section, while [Workspace tools](workspace-tools.md) explains the separate
120
+ file-tool guardrails.
data/doc/security.md CHANGED
@@ -6,8 +6,8 @@ This guide explains the trust boundaries and gives you a safe way to start work
6
6
 
7
7
  ## The short version
8
8
 
9
- - Kward and anything it launches run with your operating-system permissions.
10
- - File tools stay inside the active workspace by default, but shell commands are not sandboxed.
9
+ - Kward and its trusted host-process extensions run with your operating-system permissions.
10
+ - File tools stay inside the active workspace by default. Model-requested shell commands can also use an opt-in OS-enforced command sandbox.
11
11
  - Existing files must be read before Kward's file tools can edit or overwrite them.
12
12
  - Plugins, MCP servers, command hooks, and HTTP hooks should be configured only from sources and endpoints you trust.
13
13
  - Project skills and workspace hooks are disabled until you opt in or trust them.
@@ -16,6 +16,12 @@ This guide explains the trust boundaries and gives you a safe way to start work
16
16
 
17
17
  If a task involves secrets, production credentials, customer data, or an untrusted repository, narrow the workspace and tools before asking Kward to act.
18
18
 
19
+ ## Local model endpoints and replacement prompts
20
+
21
+ The Local provider defaults to loopback endpoints. If you set `local_base_url` to another host, Kward can send prompts, selected workspace content, attachments, and tool results to that host. Treat a non-loopback endpoint as a model provider: use TLS and authentication where appropriate, and do not assume a private-network address is harmless.
22
+
23
+ A `system_prompt.file` replacement is model-visible and may be retained in session prompt snapshots. Do not put tokens, credentials, customer data, or other secrets in that file. Replacement mode intentionally removes Kward's normal prompt layers, including workspace guidance and skill descriptions; verify it with `kward sysprompt` before using a permissive local model.
24
+
19
25
  ## A safe first run in an unfamiliar repository
20
26
 
21
27
  Start with project-provided extensions disabled, which is the default:
@@ -42,7 +48,7 @@ Before enabling or running anything:
42
48
  6. Do not add repository-provided Ruby files to `~/.kward/plugins` unless you are willing to run them as your user.
43
49
  7. Ask Kward to explain proposed edits and commands before applying them when the impact is unclear.
44
50
 
45
- For especially sensitive work, use a disposable checkout, container, virtual machine, or restricted operating-system account. Kward's own guardrails do not replace operating-system isolation.
51
+ For especially sensitive work, use a disposable checkout, container, virtual machine, or restricted operating-system account. Enable [command sandboxing](sandboxing.md) for model-requested shell commands, but remember that its first release does not sandbox the Kward host process, plugins, MCP servers, hooks, or interactive shell features.
46
52
 
47
53
  ## Workspace access is a guardrail, not a sandbox
48
54
 
@@ -50,8 +56,8 @@ Kward's built-in file tools normally resolve paths inside the active workspace.
50
56
 
51
57
  These protections reduce accidental edits. They do not contain the whole process:
52
58
 
53
- - `run_shell_command`, `!command`, `/shell`, and `/pty` run with your user permissions.
54
- - A shell command can access files, environment variables, processes, and networks available to your account.
59
+ - With `sandbox.mode: off` (the default), `run_shell_command`, `!command`, `/shell`, and `/pty` run with your user permissions.
60
+ - A non-off [command sandbox](sandboxing.md) restricts only model-requested `run_shell_command` workers and their descendants. It does not cover `!command`, `/shell`, or `/pty`.
55
61
  - Plugins, command hooks, and MCP servers are local processes with the same general operating-system access.
56
62
  - Read-before-edit applies to Kward's file tools, not to arbitrary shell commands or extension code.
57
63