kward 0.67.1 → 0.69.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/pages.yml +48 -0
  3. data/.yardopts +1 -0
  4. data/CHANGELOG.md +54 -0
  5. data/Gemfile.lock +8 -2
  6. data/README.md +37 -30
  7. data/Rakefile +14 -1
  8. data/doc/authentication.md +84 -43
  9. data/doc/code-search.md +55 -28
  10. data/doc/configuration.md +27 -2
  11. data/doc/extensibility.md +90 -129
  12. data/doc/getting-started.md +53 -57
  13. data/doc/memory.md +51 -118
  14. data/doc/personas.md +417 -0
  15. data/doc/plugins.md +55 -99
  16. data/doc/releasing.md +10 -9
  17. data/doc/rpc.md +7 -7
  18. data/doc/usage.md +125 -141
  19. data/doc/web-search.md +80 -14
  20. data/exe/kward +2 -0
  21. data/kward.gemspec +4 -0
  22. data/lib/kward/agent.rb +30 -3
  23. data/lib/kward/ansi.rb +3 -0
  24. data/lib/kward/auth/anthropic_oauth.rb +291 -0
  25. data/lib/kward/auth/file.rb +2 -0
  26. data/lib/kward/auth/github_oauth.rb +3 -0
  27. data/lib/kward/auth/openai_oauth.rb +4 -0
  28. data/lib/kward/auth/openrouter_api_key.rb +2 -0
  29. data/lib/kward/cancellation.rb +3 -0
  30. data/lib/kward/cli/auth_commands.rb +82 -0
  31. data/lib/kward/cli/commands.rb +229 -0
  32. data/lib/kward/cli/compaction.rb +25 -0
  33. data/lib/kward/cli/doctor.rb +121 -0
  34. data/lib/kward/cli/interactive_turn.rb +227 -0
  35. data/lib/kward/cli/memory_commands.rb +133 -0
  36. data/lib/kward/cli/plugins.rb +112 -0
  37. data/lib/kward/cli/prompt_interface.rb +134 -0
  38. data/lib/kward/cli/rendering.rb +378 -0
  39. data/lib/kward/cli/runtime_helpers.rb +170 -0
  40. data/lib/kward/cli/sessions.rb +376 -0
  41. data/lib/kward/cli/settings.rb +669 -0
  42. data/lib/kward/cli/slash_commands.rb +114 -0
  43. data/lib/kward/cli/stats.rb +64 -0
  44. data/lib/kward/cli/sysprompt.rb +57 -0
  45. data/lib/kward/cli/tool_summaries.rb +157 -0
  46. data/lib/kward/cli.rb +52 -2792
  47. data/lib/kward/cli_transcript_formatter.rb +40 -12
  48. data/lib/kward/clipboard.rb +1 -0
  49. data/lib/kward/compaction/file_operation_tracker.rb +3 -0
  50. data/lib/kward/compactor.rb +31 -9
  51. data/lib/kward/config_files.rb +78 -34
  52. data/lib/kward/conversation.rb +110 -13
  53. data/lib/kward/events.rb +2 -0
  54. data/lib/kward/export_path.rb +2 -0
  55. data/lib/kward/image_attachments.rb +2 -0
  56. data/lib/kward/markdown_transcript.rb +2 -0
  57. data/lib/kward/memory/manager.rb +144 -14
  58. data/lib/kward/message_access.rb +29 -2
  59. data/lib/kward/message_text.rb +45 -0
  60. data/lib/kward/model/chat_invocation.rb +2 -0
  61. data/lib/kward/model/client.rb +295 -77
  62. data/lib/kward/model/context_overflow.rb +2 -0
  63. data/lib/kward/model/context_usage.rb +14 -10
  64. data/lib/kward/model/model_info.rb +160 -4
  65. data/lib/kward/model/payloads.rb +254 -22
  66. data/lib/kward/model/retry_message.rb +2 -0
  67. data/lib/kward/model/stream_parser.rb +387 -25
  68. data/lib/kward/pan/server.rb +3 -1
  69. data/lib/kward/plugin_registry.rb +12 -0
  70. data/lib/kward/private_file.rb +2 -0
  71. data/lib/kward/prompt_interface/banner.rb +3 -0
  72. data/lib/kward/prompt_interface/composer_controller.rb +262 -0
  73. data/lib/kward/prompt_interface/composer_renderer.rb +172 -0
  74. data/lib/kward/prompt_interface/composer_state.rb +221 -0
  75. data/lib/kward/prompt_interface/key_handler.rb +365 -0
  76. data/lib/kward/prompt_interface/layout.rb +31 -0
  77. data/lib/kward/prompt_interface/overlay_renderer.rb +111 -0
  78. data/lib/kward/prompt_interface/prompt_renderer.rb +91 -0
  79. data/lib/kward/prompt_interface/question_prompt.rb +328 -0
  80. data/lib/kward/prompt_interface/runtime_state.rb +59 -0
  81. data/lib/kward/prompt_interface/screen.rb +186 -0
  82. data/lib/kward/prompt_interface/selection_prompt.rb +242 -0
  83. data/lib/kward/prompt_interface/slash_overlay.rb +102 -0
  84. data/lib/kward/prompt_interface/stream_state.rb +65 -0
  85. data/lib/kward/prompt_interface/transcript_buffer.rb +85 -0
  86. data/lib/kward/prompt_interface/transcript_renderer.rb +151 -0
  87. data/lib/kward/prompt_interface.rb +69 -1832
  88. data/lib/kward/prompts/commands.rb +2 -0
  89. data/lib/kward/prompts/templates.rb +3 -0
  90. data/lib/kward/prompts.rb +63 -7
  91. data/lib/kward/question_contract.rb +66 -0
  92. data/lib/kward/resources/avatar_kward_logo.rb +2 -0
  93. data/lib/kward/resources/pixel_logo.rb +2 -0
  94. data/lib/kward/rpc/attachment_normalizer.rb +60 -0
  95. data/lib/kward/rpc/auth_manager.rb +65 -11
  96. data/lib/kward/rpc/config_manager.rb +11 -0
  97. data/lib/kward/rpc/prompt_bridge.rb +5 -26
  98. data/lib/kward/rpc/redactor.rb +3 -0
  99. data/lib/kward/rpc/runtime_payloads.rb +4 -1
  100. data/lib/kward/rpc/server.rb +43 -11
  101. data/lib/kward/rpc/session_manager.rb +139 -347
  102. data/lib/kward/rpc/session_metrics.rb +68 -0
  103. data/lib/kward/rpc/session_tree.rb +48 -0
  104. data/lib/kward/rpc/session_tree_rows.rb +208 -0
  105. data/lib/kward/rpc/tool_event_normalizer.rb +3 -0
  106. data/lib/kward/rpc/tool_metadata.rb +3 -0
  107. data/lib/kward/rpc/transcript_normalizer.rb +50 -0
  108. data/lib/kward/rpc/transport.rb +3 -0
  109. data/lib/kward/session_diff.rb +2 -0
  110. data/lib/kward/session_store.rb +154 -25
  111. data/lib/kward/session_trash.rb +1 -0
  112. data/lib/kward/session_tree_renderer.rb +8 -41
  113. data/lib/kward/session_tree_tool_display.rb +56 -0
  114. data/lib/kward/skills/registry.rb +3 -0
  115. data/lib/kward/starter_pack_installer.rb +3 -2
  116. data/lib/kward/steering.rb +2 -0
  117. data/lib/kward/telemetry/logger.rb +3 -0
  118. data/lib/kward/telemetry/stats.rb +3 -0
  119. data/lib/kward/tools/ask_user_question.rb +20 -32
  120. data/lib/kward/tools/base.rb +8 -0
  121. data/lib/kward/tools/code_search.rb +5 -0
  122. data/lib/kward/tools/edit_file.rb +5 -0
  123. data/lib/kward/tools/fetch_content.rb +41 -0
  124. data/lib/kward/tools/fetch_raw.rb +40 -0
  125. data/lib/kward/tools/list_directory.rb +5 -0
  126. data/lib/kward/tools/read_file.rb +5 -0
  127. data/lib/kward/tools/read_skill.rb +5 -0
  128. data/lib/kward/tools/registry.rb +42 -4
  129. data/lib/kward/tools/run_shell_command.rb +5 -0
  130. data/lib/kward/tools/search/code.rb +7 -0
  131. data/lib/kward/tools/search/web.rb +20 -17
  132. data/lib/kward/tools/search/web_fetch.rb +202 -0
  133. data/lib/kward/tools/tool_call.rb +27 -5
  134. data/lib/kward/tools/web_search.rb +7 -1
  135. data/lib/kward/tools/write_file.rb +5 -0
  136. data/lib/kward/transcript_export.rb +2 -0
  137. data/lib/kward/version.rb +2 -1
  138. data/lib/kward/workspace.rb +45 -5
  139. data/templates/default/fulldoc/html/css/kward.css +1501 -0
  140. data/templates/default/fulldoc/html/images/kward_logo.png +0 -0
  141. data/templates/default/fulldoc/html/js/kward.js +296 -0
  142. data/templates/default/fulldoc/html/setup.rb +8 -0
  143. data/templates/default/layout/html/breadcrumb.erb +11 -0
  144. data/templates/default/layout/html/layout.erb +141 -0
  145. data/templates/default/layout/html/setup.rb +139 -0
  146. metadata +56 -1
data/doc/usage.md CHANGED
@@ -1,214 +1,198 @@
1
1
  # Usage
2
2
 
3
- Kward's most common commands are:
3
+ Kward has two main modes:
4
+
5
+ - **Interactive chat** for ongoing work in a project.
6
+ - **One-shot prompts** for quick questions, reviews, and summaries.
7
+
8
+ Run Kward from the workspace you want it to inspect:
4
9
 
5
10
  ```bash
6
- kward # interactive chat
7
- kward help # command overview and examples
8
- kward "Explain this project" # one-shot prompt
9
- kward init # optional first-time setup
10
- kward doctor # check local setup
11
- kward auth status # show saved credential status
12
- kward pan # Pan mode web UI
13
- kward rpc # experimental JSON-RPC backend
11
+ cd ~/code/project
12
+ kward
14
13
  ```
15
14
 
16
15
  When running from source, replace `kward` with `ruby lib/main.rb`.
17
16
 
18
- ## Starter pack
17
+ ## Common workflows
19
18
 
20
- Install Kward's starter prompts and base `AGENTS.md` into your config directory, usually `~/.kward`:
19
+ ### Understand a new project
21
20
 
22
- ```bash
23
- kward init
21
+ ```text
22
+ Explain the project structure and point out the main entry points.
24
23
  ```
25
24
 
26
- The installer downloads the pinned `kaiwood/kward-starter-pack` `v1.0.0` release, creates the config directory and base `config.json` if needed, and copies only starter-pack instruction/prompt files. It preserves the starter-pack layout in your config directory and skips files that already exist.
25
+ Useful follow-ups:
27
26
 
28
- ## Interactive chat
27
+ ```text
28
+ Where is configuration loaded?
29
+ Which files would I read first to understand authentication?
30
+ Summarize the test strategy.
31
+ ```
29
32
 
30
- Interactive mode opens a terminal composer and saves the conversation as a per-workspace session. Use it when you want Kward to inspect files, make changes, run commands, or continue a conversation over time.
33
+ ### Review changes before committing
31
34
 
32
- The composer stays available while assistant and tool output streams. If you press Enter while a response is still running, Kward queues your next prompt and sends it after the current turn finishes. Press Ctrl+C while a response is running to stop the current turn and return to the composer.
35
+ ```bash
36
+ git diff | kward "Review this diff for bugs, missing tests, and confusing naming"
37
+ ```
33
38
 
34
- Prefix input with `!` to run a local shell command from the workspace root without sending it to the model:
39
+ For larger reviews, use interactive mode so Kward can inspect related files:
35
40
 
36
41
  ```text
37
- !git status --short
42
+ Review the current git diff. If something looks risky, inspect the relevant files before recommending changes.
38
43
  ```
39
44
 
40
- ## Shell commands
45
+ ### Make a small code change
41
46
 
42
- Use `kward help` or `kward --help` to print a colored overview of available commands and examples. Use `kward help <command>` or `<command> --help` for command-specific help. Use `kward version` or `kward --version` to print the installed version.
47
+ ```text
48
+ Add a --json option to the status command. Keep the text output unchanged and add focused tests.
49
+ ```
43
50
 
44
- Use `kward doctor` to check local config, workspace, auth hints, Pan credentials, and writable directories. Use `kward auth status` to show saved credential status without printing secrets, or `kward auth logout` to remove saved OpenAI, GitHub, and OpenRouter credentials.
51
+ Kward must read an existing file in the current conversation before editing it. This guardrail helps prevent accidental overwrites.
45
52
 
46
- Use `--working-directory PATH` with any mode to run Kward from a different workspace:
53
+ ### Run local checks
47
54
 
48
- ```bash
49
- kward --working-directory ~/code/project
50
- kward --working-directory ~/code/project "Summarize this project"
51
- kward --working-directory ~/code/project pan
52
- kward --working-directory ~/code/project rpc
53
- ```
55
+ Inside interactive mode, ask Kward to run a command:
54
56
 
55
- ## One-shot prompts
57
+ ```text
58
+ Run the focused test for the CLI status command.
59
+ ```
56
60
 
57
- Command names take precedence. Invalid arguments for known commands show usage instead of becoming prompts. Anything else passed as command-line text is sent as a one-shot prompt:
61
+ Or run a shell command yourself from the composer by prefixing it with `!`:
58
62
 
59
- ```bash
60
- kward "Summarize the changes in this repository"
61
- kward Summarize the changes in this repository
63
+ ```text
64
+ !git status --short
62
65
  ```
63
66
 
64
- Use `--` before the prompt when the prompt itself starts with a command name or contains option-like text:
67
+ ## Shell commands
68
+
69
+ Useful shell commands:
65
70
 
66
71
  ```bash
67
- kward -- pan extra
68
- kward -- explain --working-directory option
72
+ kward # start interactive chat
73
+ kward "Explain this project" # ask one question and exit
74
+ kward help # show commands and examples
75
+ kward doctor # check local setup
76
+ kward login # sign in or save credentials
77
+ kward auth status # show credential status without secrets
78
+ kward sysprompt # inspect assembled instructions
79
+ kward rpc # start the experimental RPC backend
69
80
  ```
70
81
 
71
- Kward also accepts piped input:
82
+ Use another workspace without changing directories:
72
83
 
73
84
  ```bash
74
- git diff | kward "Review this diff"
85
+ kward --working-directory ~/code/project
86
+ kward --working-directory ~/code/project "Summarize this repository"
75
87
  ```
76
88
 
77
- One-shot prompts do not use Kward memory.
89
+ ## Interactive slash commands
78
90
 
79
- ## Workspace tools
91
+ Use slash commands for local actions that should not go to the model:
80
92
 
81
- Kward can use these tools during a turn:
82
-
83
- - `list_directory` and `read_file` to inspect the workspace.
84
- - `write_file` and `edit_file` to create or change files.
85
- - `run_shell_command` to run confirmed local commands.
86
- - `web_search` to search the live web.
87
- - `code_search` to find packages, clone public GitHub repositories into cache, and read bounded source snippets.
88
- - `ask_user_question` to ask structured clarification questions.
89
-
90
- Safety rules:
91
-
92
- - Existing files must be read in the current conversation before Kward can write or edit them.
93
- - Every write, edit, and shell command asks for confirmation first.
94
- - Text file reads and edits are capped at 256 KiB per file.
95
- - When successful tool results include unified diffs, the composer status shows live session totals such as `+700|-572`.
96
-
97
- ## Slash commands
98
-
99
- Use slash commands in interactive mode for local Kward actions:
100
-
101
- | Command | Purpose |
93
+ | Command | Use it when you want to... |
102
94
  | --- | --- |
103
- | `/exit`, `/quit` | Leave the session. |
104
- | `/new` | Start a fresh session. |
105
- | `/resume [path]` | Resume a saved session, or pick one when no path is given. |
106
- | `/name [name]` | Name or clear the current session name. |
107
- | `/clone` | Duplicate the current session. |
108
- | `/copy [last\|transcript]` | Copy clean assistant text or the Markdown transcript to the clipboard. |
109
- | `/export [path]` | Export the transcript as Markdown. |
110
- | `/compact [instructions]` | Summarize older conversation into a checkpoint and keep recent context. |
111
- | `/model` | Choose or type the default model. |
112
- | `/openrouter/catalog` | List the full OpenRouter model catalog. |
113
- | `/reasoning` | Choose reasoning effort. |
114
- | `/settings` | Configure overlay alignment and width. |
115
- | `/login` | Log in from inside the session. |
116
- | `/status` | Show status and auto-compaction information. |
117
- | `/stats [range]` | Show local telemetry stats when logging is enabled. |
118
- | `/memory ...` | Manage opt-in memory. |
119
- | `/redraw` | Refresh the terminal after resize or drawing glitches. |
120
-
121
- Prompt templates can add more slash commands. Plugin commands can also appear when trusted local plugins are installed.
95
+ | `/login` | sign in or save provider credentials. |
96
+ | `/model` | choose the active model. |
97
+ | `/reasoning` | choose reasoning effort. |
98
+ | `/status` | see session, model, and context status. |
99
+ | `/new` | start a fresh session. |
100
+ | `/resume` | continue a previous session. |
101
+ | `/name <name>` | name the current session. |
102
+ | `/clone` | copy the current session into a new branch. |
103
+ | `/copy last` | copy the latest assistant answer. |
104
+ | `/copy transcript` | copy the transcript as Markdown. |
105
+ | `/export notes.md` | write the transcript to a Markdown file. |
106
+ | `/compact [focus]` | summarize older context so a long chat can continue. |
107
+ | `/memory ...` | manage opt-in memory. |
108
+ | `/redraw` | fix terminal drawing after resize or glitches. |
109
+ | `/exit` | leave Kward. |
110
+
111
+ Prompt templates and plugins can add more slash commands.
122
112
 
123
113
  ## Sessions
124
114
 
125
- Interactive chats are stored as JSONL files under `~/.kward/sessions/`. Sessions are per workspace.
115
+ Interactive chats are saved under:
126
116
 
127
- Useful session commands:
128
-
129
- - `/resume` opens a picker for recent sessions.
130
- - `/name <name>` gives the current session a human-readable name.
131
- - `/clone` creates a new independent copy. Cloned sessions remember their parent and appear in the recent session picker by modification time.
132
- - `/copy` and `/copy last` copy the latest assistant response without terminal borders or ANSI styling. `/copy transcript` copies the clean Markdown transcript. Mouse selection may still include terminal UI chrome.
133
- - `/export [path]` writes a Markdown transcript. Explicit paths are resolved relative to the current workspace and must stay inside the workspace or Kward session directory.
134
- - `/compact [instructions]` summarizes older conversation into a structured Ruby-aware checkpoint. Text after `/compact ` is freeform focus text, not parsed as flags.
117
+ ```text
118
+ ~/.kward/sessions/
119
+ ```
135
120
 
136
- After compaction, Kward may need to re-read files before future edits because compacting clears remembered read-file state.
121
+ Sessions are scoped to the workspace. Use them when work spans more than one terminal sitting.
137
122
 
138
- ## Auto-compaction
123
+ Typical flow:
139
124
 
140
- Auto-compaction is enabled by default when Kward can determine the active context window. It reserves part of the model context so conversations can continue longer without suddenly exceeding the limit.
125
+ ```text
126
+ /name oauth cleanup
127
+ # work with Kward
128
+ /export oauth-notes.md
129
+ /exit
130
+ ```
141
131
 
142
- Configure it in `config.json`:
132
+ Later:
143
133
 
144
- ```json
145
- {
146
- "compaction": {
147
- "enabled": true,
148
- "reserve_tokens": 16384,
149
- "keep_recent_tokens": 20000
150
- }
151
- }
134
+ ```text
135
+ /resume
152
136
  ```
153
137
 
154
- Manual `/compact` still works when auto-compaction is disabled.
138
+ Use `/compact` when a conversation gets long. Kward summarizes older context and keeps recent context active. After compaction, it may need to re-read files before editing them again.
155
139
 
156
- ## Memory
157
-
158
- Memory is disabled by default and only applies to interactive sessions.
140
+ ## One-shot prompts
159
141
 
160
- Common commands:
142
+ One-shot prompts are best for short tasks that do not need session history:
161
143
 
162
- ```text
163
- /memory enable
164
- /memory core <text>
165
- /memory add <text>
166
- /memory list
167
- /memory why
168
- /memory promote <id>
169
- /memory relax <id>
170
- /memory forget <id>
171
- /memory disable
144
+ ```bash
145
+ kward "What does this repository do?"
146
+ git diff | kward "Review this diff"
147
+ cat error.log | kward "Explain the likely cause"
172
148
  ```
173
149
 
174
- See [Memory](memory.md) for storage locations, safety rules, auto-summary, and RPC methods.
150
+ Use `--` when your prompt starts with something that could be parsed as a command or option:
175
151
 
176
- ## Composer keys
152
+ ```bash
153
+ kward -- explain --working-directory
154
+ ```
177
155
 
178
- - Enter sends.
179
- - Shift+Enter inserts a newline.
180
- - Up/Down browse prompt history.
181
- - Ctrl+D exits from an empty prompt.
182
- - Ctrl+C stops the current response while assistant or tool output is running.
183
- - Backspace at the beginning of the prompt removes the most recent image attachment.
156
+ One-shot prompts do not use Kward memory.
184
157
 
185
- Multiline input grows the composer up to a capped height.
158
+ ## Workspace tools
186
159
 
187
- ## Image attachments
160
+ During a turn, Kward can inspect and change the workspace with tools for:
188
161
 
189
- Kward can attach images when the active model supports images. It detects:
162
+ - listing and reading files,
163
+ - creating and editing files,
164
+ - running shell commands,
165
+ - searching the web,
166
+ - fetching specific URLs,
167
+ - inspecting public source repositories,
168
+ - asking structured clarification questions.
190
169
 
191
- - pasted image file paths,
192
- - Markdown image links,
193
- - `file://` image URLs,
194
- - image data URLs.
170
+ Important guardrails:
195
171
 
196
- In the interactive composer, pasted image references appear as attachment badges instead of editable filename or base64 text. Transcripts show attachment badges and render the image inline when the terminal advertises a supported inline image protocol, such as iTerm2 or Kitty/WezTerm.
172
+ - Existing files must be read before Kward can edit or overwrite them.
173
+ - File reads and edits are bounded to avoid loading very large files by accident.
174
+ - Shell commands run from the workspace and should be treated like commands you run yourself.
197
175
 
198
- ## Pan mode
176
+ ## Images
199
177
 
200
- Pan mode starts a minimal LAN web UI with a prompt textarea and transcript:
178
+ If the active model supports images, Kward can attach image paths, Markdown image links, `file://` URLs, or image data URLs pasted into the composer.
201
179
 
202
- ```bash
203
- kward --working-directory="/path/to/workspace" pan
180
+ Use this for tasks such as:
181
+
182
+ ```text
183
+ This screenshot shows the broken layout. Find the likely CSS issue.
204
184
  ```
205
185
 
206
- From source:
186
+ ## Pan mode
187
+
188
+ Pan mode starts a simple LAN web UI:
207
189
 
208
190
  ```bash
209
- ruby lib/main.rb --working-directory="/path/to/workspace" pan
191
+ kward --working-directory ~/code/project pan
210
192
  ```
211
193
 
212
- Pan mode streams assistant output and tool calls, queues prompts submitted while a turn is running, and saves the conversation as a normal per-workspace session.
194
+ Use it only on trusted networks. It exposes the same file, shell, and web tools through a browser UI and requires credentials configured in `config.json`. See [Configuration](configuration.md).
195
+
196
+ ## RPC backend
213
197
 
214
- Configure `pan_mode.username` and `pan_mode.password` before starting it; see [Configuration](configuration.md). Pan mode is reachable on the LAN, so use it only on trusted networks.
198
+ `kward rpc` starts the experimental JSON-RPC backend for UI clients and editor integrations. Terminal users can ignore it. Integration authors should read [RPC protocol](rpc.md).
data/doc/web-search.md CHANGED
@@ -1,28 +1,94 @@
1
1
  # Web search
2
2
 
3
- Web search lets the agent search the live web. Use it when you need current facts, official docs, release notes, bug reports, pricing pages, or recent announcements.
3
+ Use web search when the answer depends on current or external information:
4
+
5
+ - current framework or dependency docs,
6
+ - release notes and migration guides,
7
+ - security advisories,
8
+ - pricing or provider pages,
9
+ - bug reports and issue discussions,
10
+ - a specific URL you want Kward to inspect.
4
11
 
5
12
  Example prompts:
6
13
 
7
14
  ```text
8
- Research the current Rails release notes and summarize migration risks.
15
+ Check the current Rails release notes and summarize migration risks for this project.
9
16
  Find the official OpenRouter docs for model configuration.
10
17
  Check whether this dependency has a recent security advisory.
18
+ Read this URL and explain the setup steps: https://example.com/docs
19
+ ```
20
+
21
+ ## How Kward researches
22
+
23
+ Kward has three web tools:
24
+
25
+ 1. `web_search` finds candidate sources.
26
+ 2. `fetch_content` reads human-readable pages.
27
+ 3. `fetch_raw` reads machine-readable files such as JSON, YAML, XML, RSS, OpenAPI specs, or plain text.
28
+
29
+ A good research flow is:
30
+
31
+ ```text
32
+ Search for the official docs, fetch the relevant page, then answer with the source URL.
33
+ ```
34
+
35
+ Kward should search first, then fetch important pages before relying on them.
36
+
37
+ ## Network behavior
38
+
39
+ Web tools are advertised to the model by default. Queries and fetched URLs are sent over the network to the selected provider or target host.
40
+
41
+ In automatic mode, provider fallback is:
42
+
43
+ 1. Exa API when `EXA_API_KEY` is configured, otherwise keyless Exa MCP.
44
+ 2. Perplexity API when configured and model-provider fallback is allowed.
45
+ 3. Gemini API with Google Search grounding when configured and model-provider fallback is allowed.
46
+ 4. DuckDuckGo HTML search, then bundled public SearXNG instances.
47
+
48
+ You do not need an API key for basic web search, but keys can improve limits or provider choice.
49
+
50
+ ## Disable web tools
51
+
52
+ Hide all web tools:
53
+
54
+ ```json
55
+ {
56
+ "web_search": {
57
+ "enabled": false
58
+ }
59
+ }
11
60
  ```
12
61
 
13
- The `web_search` tool is advertised by default so the agent can use current sources when needed. In `auto` mode the provider fallback order is:
62
+ Use this when working on private projects where no prompt should trigger external lookup.
63
+
64
+ ## Tool details
65
+
66
+ ### `web_search`
67
+
68
+ Finds candidate sources. Arguments:
69
+
70
+ - `queries`: one to four search strings.
71
+ - `max_results`: results per query, default 5, capped at 20.
72
+ - `provider`: optional `auto`, `exa`, `perplexity`, `gemini`, or `duckduckgo`.
73
+ - `recency_filter`: optional `day`, `week`, `month`, or `year`.
74
+ - `domain_filter`: optional domains to include, or domains prefixed with `-` to exclude.
75
+
76
+ ### `fetch_content`
77
+
78
+ Reads a specific HTTP or HTTPS page and extracts readable text. Use it for docs pages, articles, issues, and release notes.
79
+
80
+ Arguments:
81
+
82
+ - `url`
83
+ - `max_bytes`: default 16384, capped at 131072.
84
+ - `extract`: optional `auto`, `text`, or `markdown`.
14
85
 
15
- 1. Exa API when `EXA_API_KEY` is configured, otherwise keyless Exa MCP (`https://mcp.exa.ai/mcp`)
16
- 2. Perplexity API when configured and `allow_model_providers` is true
17
- 3. Gemini API with Google Search grounding when configured and `allow_model_providers` is true
18
- 4. Legacy DuckDuckGo HTML search, then bundled public SearXNG instances
86
+ ### `fetch_raw`
19
87
 
20
- Queries are sent over the network to the selected provider. API keys are never bundled with Kward; configure your own keys only if you want higher limits or alternate providers. Set `web_search.enabled` to `false` to hide the tool. Direct `provider: perplexity` or `provider: gemini` requests still use those providers when keys are configured.
88
+ Reads a specific HTTP or HTTPS resource without readability extraction. Use it for JSON, YAML, XML, RSS, OpenAPI specs, and plain text.
21
89
 
22
- Supported arguments:
90
+ Arguments:
23
91
 
24
- - `queries`: one to four search strings
25
- - `max_results`: results per query, default 5, capped at 20
26
- - `provider`: optional `auto`, `exa`, `perplexity`, `gemini`, `legacy`, or `duckduckgo`
27
- - `recency_filter`: optional `day`, `week`, `month`, or `year`
28
- - `domain_filter`: optional list of included domains, or excluded domains prefixed with `-`
92
+ - `url`
93
+ - `max_bytes`: default 16384, capped at 131072.
94
+ - `accept`: optional HTTP `Accept` header.
data/exe/kward CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
4
+
3
5
  require "kward"
4
6
 
5
7
  Kward::CLI.new.run
data/kward.gemspec CHANGED
@@ -13,6 +13,10 @@ Gem::Specification.new do |spec|
13
13
  spec.required_ruby_version = ">= 3.2"
14
14
 
15
15
  spec.metadata["rubygems_mfa_required"] = "true"
16
+ spec.metadata["source_code_uri"] = "https://github.com/kaiwood/kward"
17
+ spec.metadata["changelog_uri"] = "https://github.com/kaiwood/kward/blob/main/CHANGELOG.md"
18
+ spec.metadata["documentation_uri"] = "https://github.com/kaiwood/kward#readme"
19
+ spec.metadata["bug_tracker_uri"] = "https://github.com/kaiwood/kward/issues"
16
20
 
17
21
  spec.files = Dir.chdir(__dir__) do
18
22
  `git ls-files -z`.split("\x0").reject do |file|
data/lib/kward/agent.rb CHANGED
@@ -8,9 +8,21 @@ require_relative "steering"
8
8
  require_relative "telemetry/logger"
9
9
  require_relative "tools/registry"
10
10
 
11
+ # Namespace for the Kward CLI agent runtime.
11
12
  module Kward
12
13
  # Runs model turns, handles context compaction, dispatches tool calls, and
13
14
  # streams high-level events back to CLI and RPC callers.
15
+ #
16
+ # `Agent` is the main turn orchestrator. It should know what a turn means:
17
+ # append the user's input, call the model, persist assistant/tool messages,
18
+ # retry once after recoverable context overflow, apply in-flight steering, and
19
+ # emit frontend-neutral `Events::*` objects. It should not know terminal or RPC
20
+ # rendering details; callers translate events into their own UI protocol.
21
+ #
22
+ # Tool implementations own local side effects. `Client` owns provider HTTP
23
+ # details. `Conversation` owns transcript state. Keep future changes in the
24
+ # lowest layer that owns the behavior, and use `Agent` only for cross-step turn
25
+ # coordination.
14
26
  class Agent
15
27
  def initialize(client:, tool_registry: ToolRegistry.new, conversation: Conversation.new, telemetry_logger: TelemetryLogger.new)
16
28
  @client = client
@@ -67,6 +79,7 @@ module Kward
67
79
  overflow_retried = true
68
80
  next
69
81
  end
82
+ update_conversation_runtime(message)
70
83
  yield Events::AssistantMessage.new(message: message) if block_given?
71
84
  @conversation.append_assistant(message)
72
85
  steered_after_message = append_steering_events(steering_state)
@@ -200,18 +213,32 @@ module Kward
200
213
  end
201
214
  ChatInvocation.call(
202
215
  @client,
203
- @conversation.messages,
216
+ @conversation.context_messages,
204
217
  {
205
218
  tools: @tool_registry.schemas,
206
219
  on_reasoning_delta: reasoning_delta,
207
220
  on_assistant_delta: assistant_delta,
208
221
  on_retry: retry_callback,
209
222
  cancellation: cancellation,
210
- steering: steering
223
+ steering: steering,
224
+ provider: @conversation.provider,
225
+ model: @conversation.model,
226
+ reasoning: @conversation.reasoning_effort
211
227
  }
212
228
  )
213
229
  end
214
230
 
231
+ def update_conversation_runtime(message)
232
+ return unless message.is_a?(Hash)
233
+
234
+ provider = message["provider"] || message[:provider]
235
+ model = message["model"] || message[:model]
236
+ return if provider.to_s.empty? || model.to_s.empty?
237
+
238
+ @conversation.update_runtime_context!(provider: provider, model: model, reasoning_effort: @conversation.reasoning_effort)
239
+ @conversation.persist_runtime_context!
240
+ end
241
+
215
242
  def safe_answer(content)
216
243
  text = content.to_s
217
244
  return text unless claims_file_edit?(text)
@@ -222,7 +249,7 @@ module Kward
222
249
  end
223
250
 
224
251
  def claims_file_edit?(text)
225
- text.match?(/\b(I|I've|I have)\s+(changed|updated|modified|edited|created|deleted|wrote)\b/i)
252
+ text.match?(/\b(?:I|I've|I have)\s+(?:changed|updated|modified|edited|created|deleted|wrote)\s+(?:the\s+)?(?:file|files|[\w.\/-]+\.[\w-]+)\b/i)
226
253
  end
227
254
 
228
255
  def last_file_change_succeeded?
data/lib/kward/ansi.rb CHANGED
@@ -1,4 +1,6 @@
1
+ # Namespace for the Kward CLI agent runtime.
1
2
  module Kward
3
+ # ANSI color and terminal capability helpers.
2
4
  module ANSI
3
5
  ESCAPE_PATTERN = /\e\[[0-9;?]*[ -\/]*[@-~]/.freeze
4
6
  SGR_PATTERN = /\e\[[0-9;:]*m/.freeze
@@ -125,6 +127,7 @@ module Kward
125
127
  rendered.join("\n") + (string.end_with?("\n") ? "\n" : "")
126
128
  end
127
129
 
130
+ # String wrapper that strips ANSI escape sequences while preserving visible text operations.
128
131
  class MarkdownStream
129
132
  def initialize(enabled: ANSI.enabled?)
130
133
  @enabled = enabled