kward 0.78.0 → 0.80.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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +13 -2
  3. data/.github/workflows/pages.yml +1 -1
  4. data/CHANGELOG.md +82 -1
  5. data/Gemfile.lock +2 -2
  6. data/README.md +33 -38
  7. data/doc/agent-tools.md +10 -11
  8. data/doc/api.md +3 -3
  9. data/doc/authentication.md +79 -110
  10. data/doc/code-search.md +1 -1
  11. data/doc/composer.md +1 -1
  12. data/doc/configuration.md +136 -27
  13. data/doc/context-budgeting.md +6 -6
  14. data/doc/context-tools.md +2 -2
  15. data/doc/editor.md +7 -7
  16. data/doc/extensibility.md +9 -29
  17. data/doc/files.md +6 -6
  18. data/doc/getting-started.md +3 -3
  19. data/doc/git.md +8 -2
  20. data/doc/lifecycle-hooks.md +5 -4
  21. data/doc/local-models.md +130 -0
  22. data/doc/mcp.md +5 -5
  23. data/doc/permissions.md +15 -5
  24. data/doc/plugins.md +39 -4
  25. data/doc/prompt-templates.md +105 -0
  26. data/doc/providers.md +140 -0
  27. data/doc/releasing.md +11 -3
  28. data/doc/rpc.md +65 -31
  29. data/doc/sandboxing.md +142 -0
  30. data/doc/security.md +31 -10
  31. data/doc/session-management.md +2 -4
  32. data/doc/skills.md +10 -0
  33. data/doc/tabs.md +37 -0
  34. data/doc/telegram.md +138 -0
  35. data/doc/transports.md +209 -0
  36. data/doc/usage.md +11 -3
  37. data/doc/web-search.md +3 -3
  38. data/doc/workspace-tools.md +4 -4
  39. data/examples/plugins/stardate_footer.rb +10 -0
  40. data/examples/plugins/telegram/plugin.rb +39 -0
  41. data/examples/plugins/telegram/telegram_api.rb +136 -0
  42. data/examples/plugins/telegram/telegram_transport.rb +304 -0
  43. data/kward.gemspec +1 -1
  44. data/lib/kward/ansi.rb +1 -0
  45. data/lib/kward/auth/api_key_store.rb +99 -0
  46. data/lib/kward/cli/auth_commands.rb +72 -13
  47. data/lib/kward/cli/commands.rb +7 -0
  48. data/lib/kward/cli/doctor.rb +21 -0
  49. data/lib/kward/cli/git.rb +31 -8
  50. data/lib/kward/cli/plugins.rb +1 -0
  51. data/lib/kward/cli/prompt_interface.rb +7 -0
  52. data/lib/kward/cli/rendering.rb +6 -2
  53. data/lib/kward/cli/runtime_helpers.rb +4 -2
  54. data/lib/kward/cli/sessions.rb +1 -1
  55. data/lib/kward/cli/settings.rb +162 -36
  56. data/lib/kward/cli/slash_commands.rb +109 -1
  57. data/lib/kward/cli/tabs.rb +102 -37
  58. data/lib/kward/cli/transports.rb +67 -0
  59. data/lib/kward/cli/worktrees.rb +360 -0
  60. data/lib/kward/cli.rb +22 -1
  61. data/lib/kward/config_files.rb +106 -4
  62. data/lib/kward/conversation.rb +27 -8
  63. data/lib/kward/git_worktree_manager.rb +291 -0
  64. data/lib/kward/local_command_runner.rb +2 -2
  65. data/lib/kward/model/azure_openai_config.rb +54 -0
  66. data/lib/kward/model/catalog.rb +113 -0
  67. data/lib/kward/model/client.rb +364 -23
  68. data/lib/kward/model/model_info.rb +60 -1
  69. data/lib/kward/model/payloads.rb +64 -4
  70. data/lib/kward/model/provider_catalog.rb +114 -0
  71. data/lib/kward/model/sources.rb +70 -0
  72. data/lib/kward/model/stream_parser.rb +141 -39
  73. data/lib/kward/pan/index.html.erb +50 -0
  74. data/lib/kward/pan/server.rb +49 -2
  75. data/lib/kward/permissions/policy.rb +18 -4
  76. data/lib/kward/plugin_chat_runtime.rb +374 -0
  77. data/lib/kward/plugin_registry.rb +81 -8
  78. data/lib/kward/private_file.rb +9 -3
  79. data/lib/kward/prompt_interface/approval_prompt.rb +2 -0
  80. data/lib/kward/prompt_interface/composer_renderer.rb +1 -5
  81. data/lib/kward/prompt_interface/editor/auto_indent.rb +46 -0
  82. data/lib/kward/prompt_interface/editor/buffer.rb +18 -4
  83. data/lib/kward/prompt_interface/editor/controller.rb +43 -10
  84. data/lib/kward/prompt_interface/editor/modes/vibe.rb +2 -2
  85. data/lib/kward/prompt_interface/editor/renderer.rb +8 -8
  86. data/lib/kward/prompt_interface/editor/state.rb +3 -9
  87. data/lib/kward/prompt_interface/editor/syntax_highlighter.rb +184 -9
  88. data/lib/kward/prompt_interface/file_overlay.rb +2 -2
  89. data/lib/kward/prompt_interface/git_prompt.rb +7 -3
  90. data/lib/kward/prompt_interface/interactive/controller.rb +4 -4
  91. data/lib/kward/prompt_interface/interactive/renderer.rb +4 -1
  92. data/lib/kward/prompt_interface/interactive/state.rb +2 -2
  93. data/lib/kward/prompt_interface/project_browser.rb +25 -6
  94. data/lib/kward/prompt_interface/runtime_state.rb +22 -6
  95. data/lib/kward/prompt_interface/screen.rb +3 -0
  96. data/lib/kward/prompt_interface/selection_prompt.rb +7 -1
  97. data/lib/kward/prompt_interface/transcript_buffer.rb +24 -2
  98. data/lib/kward/prompt_interface.rb +71 -12
  99. data/lib/kward/prompts/commands.rb +3 -1
  100. data/lib/kward/prompts.rb +22 -10
  101. data/lib/kward/rpc/auth_manager.rb +112 -152
  102. data/lib/kward/rpc/config_manager.rb +46 -6
  103. data/lib/kward/rpc/plugin_chat_manager.rb +56 -194
  104. data/lib/kward/rpc/prompt_bridge.rb +8 -4
  105. data/lib/kward/rpc/redactor.rb +1 -1
  106. data/lib/kward/rpc/server.rb +102 -14
  107. data/lib/kward/rpc/session_manager.rb +151 -38
  108. data/lib/kward/sandbox/capabilities.rb +39 -0
  109. data/lib/kward/sandbox/command_runner.rb +28 -0
  110. data/lib/kward/sandbox/environment.rb +24 -0
  111. data/lib/kward/sandbox/linux_bubblewrap_runner.rb +71 -0
  112. data/lib/kward/sandbox/macos_seatbelt_runner.rb +96 -0
  113. data/lib/kward/sandbox/passthrough_runner.rb +13 -0
  114. data/lib/kward/sandbox/policy.rb +74 -0
  115. data/lib/kward/sandbox/runner_factory.rb +55 -0
  116. data/lib/kward/sandbox/unavailable_runner.rb +21 -0
  117. data/lib/kward/sandbox.rb +9 -0
  118. data/lib/kward/session_store.rb +110 -24
  119. data/lib/kward/skills/capture.rb +144 -0
  120. data/lib/kward/tab_driver.rb +6 -3
  121. data/lib/kward/tools/git_commit.rb +39 -0
  122. data/lib/kward/tools/registry.rb +26 -6
  123. data/lib/kward/tools/tool_call.rb +1 -0
  124. data/lib/kward/transport/gateway.rb +253 -0
  125. data/lib/kward/transport/host.rb +343 -0
  126. data/lib/kward/transport/manager.rb +179 -0
  127. data/lib/kward/transport/plugin_chat_gateway.rb +186 -0
  128. data/lib/kward/transport/runtime.rb +41 -0
  129. data/lib/kward/transport/store.rb +101 -0
  130. data/lib/kward/transport.rb +204 -0
  131. data/lib/kward/version.rb +1 -1
  132. data/lib/kward/workspace.rb +18 -3
  133. data/lib/kward/workspace_factory.rb +34 -0
  134. data/templates/default/fulldoc/html/js/kward.js +3 -0
  135. data/templates/default/kward_navigation.rb +8 -1
  136. data/templates/default/layout/html/setup.rb +5 -0
  137. metadata +41 -2
data/doc/providers.md ADDED
@@ -0,0 +1,140 @@
1
+ # Model providers
2
+
3
+ Kward can keep credentials for several model providers and switch between them without changing your conversation. Use this guide to compare authentication options, see where each provider's model list comes from, and find the names used in configuration.
4
+
5
+ For login steps and credential storage, see [Authentication](authentication.md). For every config key and environment override, see [Configuration](configuration.md#Provider_and_model_settings).
6
+
7
+ ## Quick start
8
+
9
+ Inside interactive Kward:
10
+
11
+ ```text
12
+ /login
13
+ /model
14
+ ```
15
+
16
+ `/login` connects a provider. `/model` chooses the active provider and model. The model picker can refresh the available models, accept a manual model ID, show models normally hidden by compatibility filters, or switch providers.
17
+
18
+ For example, direct OpenAI API access and ChatGPT/Codex OAuth can coexist:
19
+
20
+ 1. Run `kward login` for ChatGPT/Codex.
21
+ 2. Open `/login`, choose **API key**, then **OpenAI**.
22
+ 3. Open `/model` and choose either **Codex** or **OpenAI**.
23
+
24
+ ## Provider overview
25
+
26
+ Kward normally uses the same provider name for authentication and configuration. Direct OpenAI is the exception: authentication and private API-key storage use `openai`, while config uses `openai_api` so it cannot be confused with Codex. RPC clients also use the authentication ID.
27
+
28
+ | Provider shown in Kward | Catalog/auth ID | `provider` value | Authentication | Model source | Request API |
29
+ | --- | --- | --- | --- | --- | --- |
30
+ | Codex | — | `codex` | ChatGPT OAuth or `OPENAI_ACCESS_TOKEN` | Curated choices | ChatGPT Codex Responses, streaming |
31
+ | OpenAI | `openai` | `openai_api` | API key | Live cache with curated/manual fallback | OpenAI Responses, streaming |
32
+ | Anthropic | `anthropic` | `anthropic` | API key or Claude subscription OAuth | Curated/manual choices | Anthropic Messages, streaming |
33
+ | Azure OpenAI | `azure_openai` | `azure_openai` | API key plus Azure setup | Configured deployment | Deployment-specific Chat Completions, streaming |
34
+ | Google Gemini | `gemini` | `gemini` | API key | Live cache with curated/manual fallback | Native Gemini, streaming |
35
+ | Cerebras | `cerebras` | `cerebras` | API key | Live cache or manual ID | OpenAI-compatible Chat Completions |
36
+ | DeepSeek | `deepseek` | `deepseek` | API key | Live cache with curated/manual fallback | OpenAI-compatible Chat Completions |
37
+ | Fireworks AI | `fireworks` | `fireworks` | API key | Live cache or manual ID | OpenAI-compatible Chat Completions |
38
+ | Groq | `groq` | `groq` | API key | Live cache or manual ID | OpenAI-compatible Chat Completions |
39
+ | Mistral | `mistral` | `mistral` | API key | Live cache with curated/manual fallback | OpenAI-compatible Chat Completions |
40
+ | NVIDIA NIM | `nvidia` | `nvidia` | API key | Live cache or manual ID | OpenAI-compatible Chat Completions |
41
+ | OpenRouter | `openrouter` | `openrouter` | API key | Account-specific cache or manual ID | OpenAI-compatible Chat Completions |
42
+ | Together AI | `together` | `together` | API key | Live cache or manual ID | OpenAI-compatible Chat Completions |
43
+ | xAI | `xai` | `xai` | API key | Live cache with curated/manual fallback | OpenAI-compatible Chat Completions |
44
+ | GitHub Copilot | `copilot` | `copilot` | GitHub OAuth or `COPILOT_GITHUB_TOKEN` | Live choices with curated fallback | Copilot Responses or Chat Completions, streaming |
45
+ | Local | — | `local` | Usually none; optional local bearer key | Local server `/models` endpoint or manual ID | OpenAI-compatible Chat Completions, streaming |
46
+
47
+ “OpenAI-compatible” means Kward sends the provider's documented Chat Completions shape. It does not imply that every provider supports every OpenAI feature. Model availability, tools, images, reasoning, context limits, and billing remain provider- and model-specific.
48
+
49
+ ## IDs, model keys, and environment variables
50
+
51
+ | Provider | Model config key | Model environment variable | Credential environment variable |
52
+ | --- | --- | --- | --- |
53
+ | Codex | `openai_model` | `OPENAI_MODEL` | `OPENAI_ACCESS_TOKEN` |
54
+ | OpenAI | `openai_api_model` | `OPENAI_API_MODEL` | `OPENAI_API_KEY` |
55
+ | Anthropic | `anthropic_model` | `ANTHROPIC_MODEL` | `ANTHROPIC_API_KEY` for direct API access |
56
+ | Azure OpenAI | `azure_openai_model` | `AZURE_OPENAI_MODEL` | `AZURE_OPENAI_API_KEY` |
57
+ | Google Gemini | `gemini_model` | `GEMINI_MODEL` | `GEMINI_API_KEY` |
58
+ | Cerebras | `cerebras_model` | `CEREBRAS_MODEL` | `CEREBRAS_API_KEY` |
59
+ | DeepSeek | `deepseek_model` | `DEEPSEEK_MODEL` | `DEEPSEEK_API_KEY` |
60
+ | Fireworks AI | `fireworks_model` | `FIREWORKS_MODEL` | `FIREWORKS_API_KEY` |
61
+ | Groq | `groq_model` | `GROQ_MODEL` | `GROQ_API_KEY` |
62
+ | Mistral | `mistral_model` | `MISTRAL_MODEL` | `MISTRAL_API_KEY` |
63
+ | NVIDIA NIM | `nvidia_model` | `NVIDIA_MODEL` | `NVIDIA_API_KEY` or `NGC_API_KEY` |
64
+ | OpenRouter | `openrouter_model` | `OPENROUTER_MODEL` | `OPENROUTER_API_KEY` |
65
+ | Together AI | `together_model` | `TOGETHER_MODEL` | `TOGETHER_API_KEY` |
66
+ | xAI | `xai_model` | `XAI_MODEL` | `XAI_API_KEY` |
67
+ | GitHub Copilot | `copilot_model` | `COPILOT_MODEL` | `COPILOT_GITHUB_TOKEN` |
68
+ | Local | `local_model` | `KWARD_LOCAL_MODEL` | `KWARD_LOCAL_API_KEY` when needed |
69
+
70
+ Saved API keys live in private `<config-dir>/api_keys.json`; they do not belong in the model configuration. Environment credentials take precedence over saved API keys. OAuth files and their location overrides are documented in [Authentication](authentication.md#Custom_locations).
71
+
72
+ ## Choosing between similar providers
73
+
74
+ ### Codex or direct OpenAI
75
+
76
+ Choose **Codex** when you want ChatGPT subscription authentication and the ChatGPT Codex backend. Choose **OpenAI** when you want an OpenAI Platform API key, public `api.openai.com` billing, and the Responses API. Their credentials and model settings are intentionally separate.
77
+
78
+ ### Anthropic API or Claude subscription
79
+
80
+ Both appear as **Anthropic**. If an Anthropic API key is configured, Kward uses it before subscription OAuth. Remove or unset the API key when you specifically want the OAuth-backed subscription path.
81
+
82
+ ### OpenRouter or a direct provider
83
+
84
+ OpenRouter is useful when you want one key and its cross-provider model catalog. A direct provider is useful when you want that provider's own billing, endpoint, or native runtime. Refresh OpenRouter with `/model` or:
85
+
86
+ ```bash
87
+ kward openrouter refresh
88
+ kward openrouter list
89
+ ```
90
+
91
+ ### Cloud or Local
92
+
93
+ Choose **Local** for Ollama, LM Studio, llama.cpp, or another trusted OpenAI-compatible server. You must set the real context window yourself when the server cannot report it safely. See [Local models](local-models.md).
94
+
95
+ ## Azure OpenAI setup
96
+
97
+ Azure requires:
98
+
99
+ ```json
100
+ {
101
+ "provider": "azure_openai",
102
+ "azure_openai_endpoint": "https://example.openai.azure.com",
103
+ "azure_openai_model": "production-gpt",
104
+ "azure_openai_api_version": "2025-04-01-preview"
105
+ }
106
+ ```
107
+
108
+ The endpoint must use HTTPS and cannot contain URL credentials, a query, or a fragment. The model value is the Azure deployment name. Kward does not attempt deployment discovery using an inference key.
109
+
110
+ ## Model discovery and filtering
111
+
112
+ Kward combines several sources so a temporary catalog failure does not lock you out:
113
+
114
+ 1. refreshed live metadata, when the provider exposes model discovery;
115
+ 2. the last private local cache;
116
+ 3. conservative curated choices, where Kward has them;
117
+ 4. the currently configured model;
118
+ 5. a manual ID entered in `/model`.
119
+
120
+ When capability metadata is present, the default picker prioritizes entries that advertise generation or tool/function support and hides the others. Empty or incomplete metadata stays visible. Use **Show all models** for embedding, preview, private, or unusually described models.
121
+
122
+ Model discovery proves that an ID exists; it does not guarantee account access, tool support, image support, context size, pricing, or regional availability. Provider errors remain authoritative.
123
+
124
+ ## OAuth availability
125
+
126
+ Kward supports browser OAuth for ChatGPT/Codex and Anthropic, plus interactive GitHub login for Copilot. RPC can initiate OpenAI and Anthropic OAuth; Copilot OAuth remains CLI-only.
127
+
128
+ OpenRouter documents an official [OAuth PKCE flow](https://openrouter.ai/docs/guides/overview/auth/oauth), but Kward has not implemented it. xAI's public [API quickstart](https://docs.x.ai/developers/quickstart) documents API keys rather than a stable third-party subscription OAuth flow. Kward reports both limitations explicitly instead of presenting a login that cannot be completed safely.
129
+
130
+ ## RPC clients
131
+
132
+ RPC clients should discover providers rather than hard-code this table:
133
+
134
+ - `auth/providers` returns catalog providers and supported authentication methods;
135
+ - `auth/status` returns sanitized configured/source state;
136
+ - `models/list` returns known model entries;
137
+ - `models/refresh` refreshes a provider when supported;
138
+ - `models/set` selects the provider and model.
139
+
140
+ See the [RPC protocol](rpc.md#Config_and_auth_methods) for request shapes and unsupported OAuth capability reporting.
data/doc/releasing.md CHANGED
@@ -1,8 +1,12 @@
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
+ ## Before you begin
4
4
 
5
- Release steps before publishing:
5
+ 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.
6
+
7
+ ## Prepare the release
8
+
9
+ Before publishing:
6
10
 
7
11
  1. Update `CHANGELOG.md` for the version. Move `[Unreleased]` entries under a new version heading.
8
12
  2. Update `Kward::VERSION` in `lib/kward/version.rb`.
@@ -41,7 +45,9 @@ Release steps before publishing:
41
45
 
42
46
  8. Install the built gem locally and smoke test the `kward` executable in a clean workspace.
43
47
 
44
- Commit the version bump and create a git tag:
48
+ ## Tag and publish
49
+
50
+ Commit the version bump and create a Git tag:
45
51
 
46
52
  ```bash
47
53
  git commit -am "Bump to VERSION"
@@ -57,6 +63,8 @@ gem push kward-VERSION.gem
57
63
 
58
64
  RubyGems MFA is required for publishing. Prefer RubyGems trusted publishing for automated releases if CI publishing is added later, so long-lived API keys do not need to be stored in CI secrets.
59
65
 
66
+ ## If you need to yank a release
67
+
60
68
  If a published gem has a serious problem, you can yank it within 24 hours of pushing:
61
69
 
62
70
  ```bash
data/doc/rpc.md CHANGED
@@ -1,12 +1,25 @@
1
- # Kward RPC Protocol
1
+ # Kward RPC protocol
2
2
 
3
3
  <div class="kward-no-toc"></div>
4
4
 
5
- Kward RPC is a JSON-RPC backend protocol for trusted local UI clients. It is versioned as protocol version `1`: new methods and fields may be added in compatible releases, and clients should ignore unknown fields. Removing or changing existing methods or field meanings requires a protocol version bump. Individual capability groups may still report unsupported status in `initialize.capabilities`.
5
+ Use Kward RPC to build a trusted local interface around Kward's sessions, models, tools, and streaming turns. This page is for people building UI clients or integrations; if you use Kward only from the terminal, you can skip it.
6
6
 
7
- This page is for people building UI clients or integrations. If you use Kward from the terminal, you can skip it.
7
+ The protocol uses JSON-RPC and is currently version `1`. Compatible releases may add methods and fields, so clients should ignore fields they do not recognize. Removing a method or changing the meaning of an existing field requires a protocol version bump. Individual capability groups may still report that they are unsupported in `initialize.capabilities`.
8
8
 
9
- Prompt history search is a CLI terminal feature only. RPC clients own their composer/input UX and Kward does not currently expose prompt-history read, append, or search methods over RPC.
9
+ ## Build a client
10
+
11
+ A typical client launches the server, sends `initialize`, creates or resumes a session, starts a turn, and renders `turn/event` notifications. Use these sections for the next step:
12
+
13
+ | You need to... | Start here |
14
+ | --- | --- |
15
+ | Connect and negotiate capabilities | [Launch](#Launch), [Framing](#Framing), and [Initialization](#Initialization) |
16
+ | Open, resume, branch, or export a conversation | [Session methods](#Session_methods) |
17
+ | Send input and render a response | [Turn methods](#Turn_methods) and [Turn notifications](#Turn_notifications) |
18
+ | Handle tool approval or structured questions | [Tool approval bridge](#Tool_approval_bridge) and [UI question bridge](#UI_question_bridge) |
19
+ | Show model, runtime, auth, or configuration controls | [Runtime methods](#Runtime_methods), [Model methods](#Model_methods), and [Config and auth methods](#Config_and_auth_methods) |
20
+ | Discover tools, MCP servers, prompts, skills, or plugins | [Tool and prompt methods](#Tool_and_prompt_methods) |
21
+
22
+ Prompt history search is a CLI terminal feature only. RPC clients own their composer/input UX and Kward does not expose prompt-history read, append, or search methods over RPC.
10
23
 
11
24
  ## Launch
12
25
 
@@ -47,30 +60,31 @@ Result fields:
47
60
  - `experimental`: `false`.
48
61
  - `capabilities`: includes frontend-neutral capability groups.
49
62
 
50
- Detailed capability fields include:
63
+ Read `capabilities` at runtime instead of assuming every feature is available. Its groups describe:
51
64
 
52
65
  - `transcript`: Kward transcript format support, including normalized messages, image/tool support, compaction summaries, and restored assistant reasoning as Pi-compatible `thinking` content blocks.
53
- - `sessions`: explicit RPC session mode, JSONL persistence, supported session methods, startup auto-resume capability/default, immediate transcript support for auto-resume, RPC list support, active live-session discovery, supported linear-session fork methods, supported compaction, supported tree navigation with labels and branch summarization, explicit unsupported import support, and unsupported live session updates reported with `notification: "session/updated"`.
54
- - `turns`: async turn mode, per-session concurrency, active/recent turn listing, provider-gated native busy-input steering, queued follow-up input, best-effort cancellation, recent in-memory event replay behavior, per-turn options for model/reasoning/tool scope/tool approval, and structured client context for editor integrations.
55
- - `pluginChats`: optional plugin-owned chats. The capability lists opted-in chat types and methods. Clients must explicitly subscribe before receiving `pluginChat/event` notifications; plugin chats are independent from workspace sessions.
56
- - `events`: `turn/event` notification details, assistant/reasoning event names, normalized tool metadata, tool update/result events, diff result support, configured workspace guardrail status, focused context and context-budget stats tool support, and explicit unsupported shell changed-file detection/session update flags.
66
+ - `sessions`: explicit RPC session mode, JSONL persistence, and methods for listing, auto-resume, live-session discovery, linear forking, compaction, and labeled tree navigation with branch summaries. Import is unsupported. Live session updates are also unsupported but reserve the `session/updated` notification name. Git worktree bindings are reported as interactive-TUI-only.
67
+ - `turns`: asynchronous turns, per-session concurrency, active and recent turn lists, busy-input steering when the provider supports it, queued follow-ups, best-effort cancellation, and recent in-memory event replay. Per-turn options cover model, reasoning, tool scope, and tool approval, with structured client context for editor integrations.
68
+ - `pluginChats`: optional plugin-owned chats. The capability lists opted-in chat types and methods. Clients must explicitly subscribe before receiving `pluginChat/event` notifications; plugin chats are independent from workspace sessions. A type may also report `transport: true` when a trusted external transport is allowed to target it; RPC opt-in and external transport opt-in remain separate.
69
+ - `events`: the `turn/event` contract, assistant and reasoning events, normalized tool metadata, tool updates and results, diff support, workspace guardrail status, focused-context and context-budget statistics tools, and explicitly unsupported shell changed-file and session-update flags.
57
70
  - `attachments`: supported input attachment contract for `turns/start`, with accepted base64 image MIME types and a stable max byte value.
58
- - `models`: model/reasoning RPC methods, explicit OpenRouter catalog listing, exposed model fields, and no scoped model support.
59
- - `runtime`: supported state/stats methods with message-count stats and OpenAI/Codex context usage. Cumulative token and cost stats are not computed.
71
+ - `models`: model listing, refresh, selection, and exposed metadata across providers. Scoped model selection is not supported.
72
+ - `runtime`: runtime state, message-count statistics, and OpenAI/Codex context usage. Kward does not yet compute cumulative token or cost statistics.
60
73
  - `lifecycleHooks`: supported lifecycle hook events, decisions, command/plugin/workspace/HTTP/async hook availability, audit log path, hook approval routing through tool approval, and hook notifications (`hook/event`, `hook/message`).
61
74
  - `runtimeSettings`: live `runtime/updateSetting` support for `defaultModel` and `defaultThinkingLevel`, plus `runtime/reload`.
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.
75
+ - `auth`: available providers and authentication methods, private API-key storage, sanitized status, and logout. OpenAI and Anthropic OAuth are supported; Copilot OAuth is CLI-only, OpenRouter PKCE is not implemented, and xAI has no supported stable third-party flow.
63
76
  - `memory`: opt-in structured memory support, interactive prompt injection only, JSON/JSONL local storage, and dedicated `memory/*` methods.
64
77
  - `commands`: supported `commands/list` capability for prompt, skill, and plugin command sources, plus plugin execution through `commands/run` or plugin slash turns.
65
- - `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.
78
+ - `skillCapture`: capture a reviewed personal `SKILL.md` from any saved session’s active branch through `skills/captureSessions`, `skills/captureDraft`, and `skills/saveCapturedDraft`.
79
+ - `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`. It does not support MCP resources, prompts, sampling, or Streamable HTTP.
66
80
  - `startupResources`: supported startup resource listing for context, skills, prompts, and plugins.
67
81
  - `extensionUi`: question bridge support via `ui/question` and `ui/answerQuestion`, plus plugin footer updates via `ui/footer`; other UI primitives are explicitly unsupported.
68
82
  - `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`.
83
+ - `security`: trusted-local behavior and optional per-turn tool approval. By default, RPC turns have no workspace mutation guard or tool approval, so shell commands and file changes can run. Clients can inspect file-tool guardrails through `capabilities.events.tools.workspaceGuardrails` and `runtime/state.workspaceGuardrailsEnabled`. `security.sandbox` reports the command sandbox mode, enforcement backend, and filesystem and network capabilities; session pinning and one-time elevation are unsupported. See [Command sandboxing](sandboxing.md) for the boundary and its limits.
70
84
  - `export`: supported transcript export formats. Currently `markdown` and `html`; default is `markdown`.
71
85
  - `starterPack`: explicitly unsupported (`supported: false`, reason `cliOnlyInstallCommand`). Use `kward init` from the shell.
72
86
  - `shell`: explicitly unsupported (`supported: false`, reason `interactiveTuiOnly`) because `/shell` is the local embedded TUI shell.
73
- - `logging`: local redacted telemetry logging support, the log directory, enabled categories, `methods: ["logging/stats", "logging/tokenCsv"]`, `usageCsv` sub-capability with bucket support, JSONL format, rotation (10 MB, manual retention), config key `logging`, env prefix `KWARD_LOGGING`, and redacted-metadata-only content.
87
+ - `logging`: local redacted telemetry, its directory and enabled categories, `logging/stats` and `logging/tokenCsv`, bucketed `usageCsv` support, JSONL storage, and 10 MB rotation with manual retention. Logs contain redacted metadata only. Configuration uses the `logging` key and `KWARD_LOGGING` environment prefix.
74
88
 
75
89
  ### `shutdown`
76
90
 
@@ -119,7 +133,7 @@ Params:
119
133
  - `name`: optional session name.
120
134
  - `resumeLast`: optional boolean. Defaults to the configured `sessions.auto_resume` behavior when omitted by clients that use `sessions/create` for startup. `false` forces a fresh session.
121
135
 
122
- Creates a persisted Kward session and returns session metadata. The response includes `activePersonaLabel` so clients can render the correct avatar immediately. When `resumeLast` is enabled, no `name` is provided, and `sessions.auto_resume` is `true`, Kward resumes the remembered last session for the workspace instead of creating a fresh file; that auto-resume response also includes `resumed: true` and normalized `messages` so clients do not need to briefly render a fresh avatar while fetching transcript state.
136
+ Creates a persisted Kward session and returns its metadata. The response includes `activePersonaLabel` so clients can render the correct avatar immediately. If `resumeLast` and `sessions.auto_resume` are both enabled and no `name` is provided, Kward resumes the last session remembered for the workspace. That response includes `resumed: true` and normalized `messages`, allowing clients to render the restored transcript immediately.
123
137
 
124
138
  ### `sessions/resume`
125
139
 
@@ -170,7 +184,7 @@ Returns:
170
184
  ```json
171
185
  {
172
186
  "summary": "Compaction summary",
173
- "firstKeptEntryId": "message:2",
187
+ "firstKeptEntryId": "a13f8c42b7d94e10c5f8a3b6d2e9f401",
174
188
  "tokensBefore": 1234,
175
189
  "details": {
176
190
  "read_files": [],
@@ -192,12 +206,12 @@ Returns forkable user-message entries for the active session:
192
206
  ```json
193
207
  {
194
208
  "messages": [
195
- { "entryId": "message:0", "text": "User message text" }
209
+ { "entryId": "a13f8c42b7d94e10c5f8a3b6d2e9f401", "text": "User message text" }
196
210
  ]
197
211
  }
198
212
  ```
199
213
 
200
- `entryId` values are stable message-index IDs within the linear session. `text` is compact display text.
214
+ `entryId` values are opaque, stable persisted tree-entry IDs. Clients must use the IDs returned by Kward rather than constructing them. `text` is compact display text.
201
215
 
202
216
  ### `sessions/fork`
203
217
 
@@ -548,7 +562,7 @@ Refreshes config-backed runtime state and returns `{ "ok": true, "message": "Res
548
562
 
549
563
  ## Logging methods
550
564
 
551
- The `logging` capability reports local redacted telemetry logging support, the log directory, enabled categories, `methods: ["logging/stats", "logging/tokenCsv"]`, `usageCsv` sub-capability with bucket support, JSONL format with 10 MB rotation and manual retention, config key `logging`, env prefix `KWARD_LOGGING`, and redacted-metadata-only content. Logging methods require logging to be enabled by config or environment for at least one category.
565
+ Check the `logging` capability to see whether local redacted telemetry is available. It reports the log directory, enabled categories, supported methods, bucketed CSV support, JSONL storage, and 10 MB rotation with manual retention. Logs contain redacted metadata only. Configure logging with the `logging` key or `KWARD_LOGGING` environment prefix, and enable at least one category before calling these methods.
552
566
 
553
567
  ### `logging/stats`
554
568
 
@@ -558,7 +572,7 @@ Params:
558
572
 
559
573
  Accepted units are minutes, hours, days, weeks, months, and years. Ranges use UTC calendar periods: `1 month` means the current calendar month so far, and `2 months` means the previous month plus the current month so far. Invalid ranges return an invalid-params error with usage text.
560
574
 
561
- Returns structured stats for enabled categories only, including the requested range, log directory, record counts by category/event, `usageStats` token totals, performance duration summaries, tool call summaries, and error counts by event/class/provider/code. Error messages are not included in the stats response.
575
+ Returns statistics for enabled categories over the requested range. The response includes the log directory, record counts by category and event, `usageStats` token totals, performance durations, tool call summaries, and error counts by event, class, provider, and code. It does not include error messages.
562
576
 
563
577
  ### `logging/tokenCsv`
564
578
 
@@ -681,7 +695,15 @@ Returns `{ "memories": [] }`.
681
695
 
682
696
  ### `models/list`
683
697
 
684
- Returns known model entries from the current client/config backend. OpenRouter entries come from the local OpenRouter model cache when present; otherwise Kward falls back to defaults/currently configured options. Refresh the cache with the CLI-only `kward openrouter refresh` command. Entries use `{ "provider", "id", "name", "reasoning", "reasoningEffort", "contextWindow", "current" }`.
698
+ Returns known model entries from configured provider catalogs, including cached and curated fallbacks. Entries use `{ "provider", "id", "name", "reasoning", "reasoningEffort", "contextWindow", "current" }`.
699
+
700
+ ### `models/refresh`
701
+
702
+ Params:
703
+
704
+ - `provider`: optional configured provider name. Defaults to the active provider.
705
+
706
+ Refreshes that provider's live model catalog when discovery is supported and returns the complete sanitized model list. Providers without live discovery retain configured or curated choices.
685
707
 
686
708
  ### `models/current`
687
709
 
@@ -692,7 +714,7 @@ Returns the current model entry with `provider`, `id`, `name`, `reasoning`, `rea
692
714
  Params:
693
715
 
694
716
  - `model`: model ID string.
695
- - `provider`: optional provider hint, currently `Codex` or `OpenRouter`; defaults to the active provider.
717
+ - `provider`: optional provider name or catalog ID; defaults to the active provider.
696
718
 
697
719
  Updates the config-backed provider model and returns the current model payload.
698
720
 
@@ -745,6 +767,16 @@ Params:
745
767
 
746
768
  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
769
 
770
+ ### `skills/captureSessions`, `skills/captureDraft`, and `skills/saveCapturedDraft`
771
+
772
+ Use this two-step workflow to capture a personal skill from a saved session:
773
+
774
+ 1. Call `skills/captureSessions` to list available persisted session sources.
775
+ 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.
776
+ 3. Review and edit `content`, then call `skills/saveCapturedDraft`. Set `overwrite: true` only after explicitly confirming replacement of an existing personal skill.
777
+
778
+ Captured skills are saved under the Kward config directory, are not activated automatically, and no file is written until the final save call succeeds.
779
+
748
780
  ### `resources/startup`
749
781
 
750
782
  Params:
@@ -782,30 +814,32 @@ Params:
782
814
 
783
815
  - `values`: object of config keys and values.
784
816
 
785
- Updates config, including secret values, and returns a redacted config object. The stored file contains the supplied values.
817
+ Updates non-secret config and returns a redacted config object. Provider API-key fields are rejected; use `auth/loginWithApiKey` so keys go to private credential storage.
786
818
 
787
819
  ### `auth/status`
788
820
 
789
- Returns whether OpenAI OAuth, Anthropic OAuth, OpenAI access token env, and OpenRouter API key env/config are available.
821
+ Returns sanitized status plus catalog provider entries. It reports configured/source booleans but never credential values.
790
822
 
791
823
  ### `auth/providers`
792
824
 
793
- Returns frontend-neutral provider cards for OpenAI OAuth, Anthropic OAuth, OpenRouter API-key auth, and GitHub/Copilot status. Provider cards report whether credentials are configured, whether they came from stored config or environment variables, and whether stored credentials can be removed.
825
+ Returns every catalog provider with `runtimeId`, `configured`, `source`, `canLogout`, and `authMethods`. Each auth method reports `id` (`api_key` or `oauth`), `supported`, `configured`, optional `source`, callback support, and an explicit reason when unsupported. Clients should discover this response dynamically; [Model providers](providers.md) is the corresponding human-readable reference.
794
826
 
795
827
  ### `auth/loginWithApiKey`
796
828
 
797
829
  Params:
798
830
 
799
- - `providerId`: currently `openrouter`.
800
- - `apiKey`: API key secret.
831
+ - `providerId`: any catalog provider that accepts API keys;
832
+ - `apiKey`: API key secret;
833
+ - `configuration`: required for Azure OpenAI, with `endpoint`, `deployment`, and `apiVersion`.
801
834
 
802
- Stores the API key with `0600` file permissions, refreshes client config, and returns a redacted message payload. Secret values are not returned.
835
+ Stores the key in private `<config-dir>/api_keys.json`, refreshes client config, and returns only provider/method/status metadata. Keys and raw sensitive provider responses are never returned.
803
836
 
804
837
  ### `auth/logoutProvider`
805
838
 
806
839
  Params:
807
840
 
808
- - `providerId`: `openai`, `anthropic`, or `openrouter`.
841
+ - `providerId`: catalog provider ID;
842
+ - `authMethod`: optional `api_key` or `oauth`; omitting it removes all stored methods Kward can remove for that provider.
809
843
 
810
844
  Removes stored credentials only. Environment variables remain active and are still reported by `auth/providers`.
811
845
 
@@ -816,7 +850,7 @@ Params:
816
850
  - `providerId`: currently `openai` or `anthropic`.
817
851
  - `timeoutSeconds`: optional callback wait timeout.
818
852
 
819
- Provider-scoped wrapper around the OpenAI or Anthropic OAuth flow. The result includes `providerId`, `loginId`, `authorizationUrl`, `redirectUri`, and `status`.
853
+ Provider-scoped wrapper around the OpenAI or Anthropic OAuth flow. The result includes `providerId`, `loginId`, `authorizationUrl`, `redirectUri`, and `status`. Copilot is reported as CLI-only. OpenRouter's official PKCE flow is not yet implemented by Kward, and xAI has no supported stable third-party OAuth flow; both return explicit sanitized unsupported errors.
820
854
 
821
855
  ### `auth/startOpenAILogin`
822
856
 
data/doc/sandboxing.md ADDED
@@ -0,0 +1,142 @@
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
+ ## Worktree tabs
67
+
68
+ An active worktree-backed tab uses a strict `workspace_write` policy for its
69
+ model-requested command workers, regardless of the global `sandbox.mode` or
70
+ `tools.workspace_guardrails` settings. The writable root is exactly the linked
71
+ worktree and no configured additional writable roots are carried into the tab.
72
+ The configured child-network setting is preserved.
73
+
74
+ If the current platform cannot provide filesystem enforcement, Kward refuses to
75
+ activate the worktree instead of falling back to an unrestricted command
76
+ worker. The strict agent also disables configured MCP clients and lifecycle
77
+ hooks because they run in the Kward host process rather than inside the command
78
+ sandbox.
79
+
80
+ This does not contain the interactive `/shell`, `!command`, or `/pty` features;
81
+ those are user-directed host-process operations. Generic model-requested shell
82
+ commands still cannot write Git metadata. Active worktree tabs additionally
83
+ expose a narrow `git_commit` tool for explicit agent-requested commits; it runs
84
+ through the trusted host-side Git workflow rather than widening the shell
85
+ sandbox. The interactive `/git` flow remains available for manual review and
86
+ commit.
87
+
88
+ ## Platform support
89
+
90
+ | Platform | Backend | Status |
91
+ | --- | --- | --- |
92
+ | macOS | Seatbelt through `/usr/bin/sandbox-exec` | Supported for command workers. Kward checks availability at runtime. |
93
+ | Linux | Bubblewrap | Supported when `bwrap` can create the required namespaces. |
94
+ | Windows | None | Unsupported. A requested non-off policy fails closed. |
95
+
96
+ On Debian or Ubuntu, install Bubblewrap with `sudo apt install bubblewrap`; on
97
+ Fedora, use `sudo dnf install bubblewrap`. A present `bwrap` executable can
98
+ still be prevented from creating namespaces by host policy. In that case,
99
+ Kward fails the command closed instead of running it unrestricted.
100
+
101
+ The macOS `sandbox-exec` utility is deprecated by Apple. Kward therefore treats
102
+ it as a capability-detected backend and verifies enforcement with platform
103
+ integration tests. It is not a promise that future macOS releases will retain
104
+ this interface.
105
+
106
+ ## Boundaries and limits
107
+
108
+ The current implementation protects **model-requested command workers only**.
109
+ It does not sandbox:
110
+
111
+ - the Kward Ruby host process;
112
+ - model-provider, search-provider, or RPC traffic;
113
+ - trusted Ruby plugins;
114
+ - MCP servers, lifecycle hooks, `/shell`, `!command`, or `/pty`.
115
+
116
+ Sandboxed command workers receive a minimal environment: Kward preserves only
117
+ basic terminal, locale, and path variables, then supplies a private `HOME` and
118
+ temporary directory. Credentials and runtime-injection variables are not
119
+ inherited. On macOS, Seatbelt also denies reads from common credential locations
120
+ under the host home directory, including `.kward`, `.ssh`, `.aws`, `.gnupg`, and
121
+ selected cloud/CLI configuration directories.
122
+
123
+ This is defense in depth, not complete secret-file read isolation: commands
124
+ still receive system and development-tool reads needed for normal local work.
125
+ On Linux, Bubblewrap provides a read-only view of the host filesystem outside
126
+ its explicitly writable paths; it does not hide every file your account can
127
+ read. For sensitive repositories, use a disposable checkout, VM, or container
128
+ in addition to Kward's command sandbox.
129
+
130
+ The RPC `initialize.capabilities.security.sandbox` payload reports the active
131
+ mode, backend, and whether filesystem and child-network enforcement are active.
132
+ It also reports unsupported features, including session pinning and one-time
133
+ sandbox elevation; those are not available yet.
134
+
135
+ ## Related guides
136
+
137
+ - [Security and trust](security.md) explains Kward's broader trust boundaries.
138
+ - [Permissions](permissions.md) controls whether Kward starts a model-requested
139
+ tool; it does not constrain a command after it starts.
140
+ - [Configuration](configuration.md#Command_sandboxing) covers the full config
141
+ section, while [Workspace tools](workspace-tools.md) explains the separate
142
+ file-tool guardrails.