kward 0.83.0 → 0.84.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -15
  3. data/CONTRIBUTING.md +74 -0
  4. data/Gemfile.lock +8 -2
  5. data/README.md +21 -1
  6. data/Rakefile +46 -2
  7. data/SECURITY.md +31 -0
  8. data/doc/api.md +4 -0
  9. data/doc/composer.md +1 -1
  10. data/doc/configuration.md +68 -21
  11. data/doc/editor.md +28 -13
  12. data/doc/files.md +8 -4
  13. data/doc/getting-started.md +3 -0
  14. data/doc/pan.md +19 -15
  15. data/doc/platform-support.md +48 -0
  16. data/doc/security.md +3 -2
  17. data/doc/shell.md +62 -45
  18. data/doc/troubleshooting.md +12 -2
  19. data/doc/usage.md +5 -5
  20. data/kward.gemspec +5 -4
  21. data/lib/kward/agent.rb +6 -3
  22. data/lib/kward/ansi.rb +110 -10
  23. data/lib/kward/cli/auth_commands.rb +34 -13
  24. data/lib/kward/cli/commands.rb +83 -62
  25. data/lib/kward/cli/doctor.rb +39 -17
  26. data/lib/kward/cli/hook_commands.rb +22 -12
  27. data/lib/kward/cli/interactive_turn.rb +48 -7
  28. data/lib/kward/cli/project_skills_commands.rb +8 -4
  29. data/lib/kward/cli/prompt_interface.rb +27 -0
  30. data/lib/kward/cli/rendering.rb +15 -9
  31. data/lib/kward/cli/runtime_helpers.rb +118 -55
  32. data/lib/kward/cli/slash_commands.rb +12 -14
  33. data/lib/kward/cli/tabs.rb +83 -12
  34. data/lib/kward/cli/tool_summaries.rb +14 -0
  35. data/lib/kward/cli.rb +45 -7
  36. data/lib/kward/cli_transcript_formatter.rb +11 -4
  37. data/lib/kward/config_files.rb +82 -68
  38. data/lib/kward/detached_run.rb +44 -0
  39. data/lib/kward/interactive_pty_runner.rb +102 -28
  40. data/lib/kward/{ekwsh.rb → kwsh.rb} +35 -16
  41. data/lib/kward/kwshrc.rb +233 -0
  42. data/lib/kward/markdown_code_block.rb +136 -0
  43. data/lib/kward/model/client.rb +34 -22
  44. data/lib/kward/model/provider_catalog.rb +5 -0
  45. data/lib/kward/model/stream_parser.rb +20 -4
  46. data/lib/kward/pan/index.html.erb +3 -3
  47. data/lib/kward/pan/server.rb +23 -3
  48. data/lib/kward/persistent_shell_session.rb +119 -26
  49. data/lib/kward/project_files.rb +2 -2
  50. data/lib/kward/prompt_interface/composer_renderer.rb +44 -40
  51. data/lib/kward/prompt_interface/composer_state.rb +33 -24
  52. data/lib/kward/prompt_interface/editor/auto_indent.rb +24 -22
  53. data/lib/kward/prompt_interface/editor/controller.rb +30 -33
  54. data/lib/kward/prompt_interface/editor/endwise.rb +13 -4
  55. data/lib/kward/prompt_interface/editor/modes/vibe.rb +289 -44
  56. data/lib/kward/prompt_interface/editor/renderer.rb +108 -6
  57. data/lib/kward/prompt_interface/editor/runner.rb +362 -0
  58. data/lib/kward/prompt_interface/editor/runner_state.rb +78 -0
  59. data/lib/kward/prompt_interface/editor/state.rb +10 -10
  60. data/lib/kward/prompt_interface/editor/syntax_highlighter.rb +68 -6
  61. data/lib/kward/prompt_interface/editor/vibe_state.rb +3 -3
  62. data/lib/kward/prompt_interface/file_overlay.rb +71 -15
  63. data/lib/kward/prompt_interface/key_handler.rb +67 -0
  64. data/lib/kward/prompt_interface/overlay_renderer.rb +7 -5
  65. data/lib/kward/prompt_interface/project_browser.rb +415 -14
  66. data/lib/kward/prompt_interface/runtime_state.rb +50 -1
  67. data/lib/kward/prompt_interface/screen.rb +2 -2
  68. data/lib/kward/prompt_interface/selection_prompt.rb +3 -1
  69. data/lib/kward/prompt_interface/slash_overlay.rb +19 -4
  70. data/lib/kward/prompt_interface/transcript_renderer.rb +12 -7
  71. data/lib/kward/prompt_interface.rb +93 -18
  72. data/lib/kward/prompts/commands.rb +1 -1
  73. data/lib/kward/prompts.rb +1 -1
  74. data/lib/kward/pty_output_sink.rb +47 -0
  75. data/lib/kward/rpc/transcript_normalizer.rb +7 -3
  76. data/lib/kward/scratchpad_languages.rb +74 -0
  77. data/lib/kward/scratchpad_runner.rb +155 -29
  78. data/lib/kward/shell_prompt.rb +2 -0
  79. data/lib/kward/terminal_keys.rb +12 -0
  80. data/lib/kward/terminal_text.rb +121 -0
  81. data/lib/kward/text_matcher.rb +18 -0
  82. data/lib/kward/tools/open_editor.rb +41 -0
  83. data/lib/kward/tools/registry.rb +13 -4
  84. data/lib/kward/tools/tool_call.rb +2 -1
  85. data/lib/kward/version.rb +1 -1
  86. data/templates/default/fulldoc/html/css/kward.css +0 -125
  87. data/templates/default/fulldoc/html/images/kward_workflow.svg +52 -0
  88. data/templates/default/fulldoc/html/setup.rb +1 -1
  89. data/templates/default/kward_navigation.rb +1 -0
  90. data/templates/default/layout/html/footer.erb +10 -0
  91. data/templates/default/layout/html/headers.erb +23 -0
  92. data/templates/default/layout/html/layout.erb +6 -18
  93. data/templates/default/layout/html/setup.rb +41 -2
  94. metadata +36 -8
  95. data/templates/default/fulldoc/html/images/kward_screen_1.png +0 -0
data/doc/editor.md CHANGED
@@ -23,7 +23,7 @@ cd ~/code/my-project
23
23
  kward edit lib/kward/agent.rb
24
24
  ```
25
25
 
26
- Kward uses the current directory as the workspace, opens the file in the integrated editor, and exits when you close the editor. Use `--working-directory` when the file belongs to another workspace:
26
+ Kward uses the current directory as the workspace, opens the file in the integrated editor, and exits when you close the editor. During an interactive chat session, you can also ask Kward to open a workspace file for you; it uses the `open_editor` tool when that capability is available. Opening the editor does not change or save the file unless you choose to do so. Use `--working-directory` when the file belongs to another workspace:
27
27
 
28
28
  ```bash
29
29
  kward --working-directory ~/code/my-project edit lib/kward/agent.rb
@@ -43,18 +43,23 @@ For a nested project tree, run:
43
43
  /files
44
44
  ```
45
45
 
46
- In the tree browser, use `↑`/`↓` to move, `←`/`→` to collapse or expand directories, `Enter` to toggle a directory or open a file, `Tab` or `/` to search, `i` to show or hide Git-ignored files, `@` to insert the selected file as an `@path` mention, and `Esc` to close. When you open a file from `/files`, quitting the editor returns to the browser at the same position.
46
+ In the tree browser, use `↑`/`↓` to move, `←`/`→` to collapse or expand directories, `Enter` to toggle a directory or open a file, `Tab` or `/` to search, `i` to show or hide Git-ignored files, `f` to create a file, `d` to create a directory, `r` to rename the selected entry, `Backspace` to delete after confirmation, `@` to insert the selected file as an `@path` mention, and `Esc` to close. Create and rename names are entered in the prompt and must be single entry names. When you open a file from `/files`, quitting the editor returns to the browser at the same position.
47
47
 
48
48
  For an unsaved buffer, open a scratchpad:
49
49
 
50
50
  ```text
51
51
  /scratchpad
52
52
  /scratchpad markdown
53
- /scratchpad ruby
53
+ /scratchpad js
54
+ /scratchpad python
55
+ /scratchpad help
54
56
  ```
55
57
 
56
- Scratchpads start as virtual editor buffers named `scratchpad.txt`, `scratchpad.md`, or `scratchpad.rb`. In Vibe mode, save one to a real file with `:w filename`.
57
- Ruby scratchpads can run with `:run` in Vibe mode or `Ctrl+R` in Modern mode; Kward executes the buffer and writes combined output after `__END__`, replacing any previous output there.
58
+ Scratchpads accept canonical language names and familiar file-extension shortcuts. For example, `js` selects JavaScript, `py` selects Python, `rb` selects Ruby, `yml` selects YAML, `cs` selects C#, and `cpp` selects C++. Use `/scratchpad help` to print the complete list of names and aliases.
59
+
60
+ All 26 built-in syntax-highlighted languages are available: Ruby, ERB, Crystal, Elixir, Julia, JavaScript, TypeScript, JSON, Markdown, YAML, Shell, Makefile, HTML, CSS, SCSS, Python, Go, Rust, Java, C#, C, C++, Swift, Kotlin, Lua, and SQL. Markdown buffers also apply the tagged language highlighter, auto-indentation, and endwise behavior inside fenced code blocks, such as a fence tagged `ruby` or `js`; unknown tags remain readable as plain text. Scratchpads use a matching virtual filename such as `scratchpad.js` or `scratchpad.py`; in Vibe mode, save one to a real file with `:w filename`.
61
+
62
+ Supported editable buffers can run with `:run` in Vibe mode or `Ctrl+R` in Modern mode. This works for both scratchpads and normal editor files. Kward runs the current in-memory buffer, including unsaved changes, without saving the file automatically. It opens a read-only output pane in the lower half of the editor with the captured output, exit status, and duration. Drag with the mouse to make a virtual selection inside the output, then press `Ctrl+C` or `Cmd+C` to copy it (`y` in Vibe mode). Only the selected output text is copied; pane borders are excluded. `Cmd+C` requires the terminal to forward the Command key to Kward. Press `Esc` to return to editing, use the arrow or page keys to scroll, and press `Ctrl+C` without a selection to cancel a running buffer. Runnable languages are Ruby, JavaScript, TypeScript, Python, Shell, Lua, Julia, Elixir, Crystal, Go, and Swift; other languages currently provide editing and highlighting only.
58
63
 
59
64
  ```ruby
60
65
  puts "foo"
@@ -63,14 +68,14 @@ __END__
63
68
  foo
64
69
  ```
65
70
 
66
- The next run receives the current `__END__` section as Ruby `DATA`, then replaces it with the new output.
71
+ The next run receives the current `__END__` section as Ruby `DATA`; the output window is refreshed without changing the source buffer.
67
72
 
68
73
  You can also type a relative path yourself and press `Enter`. If the file does not exist, Kward asks whether to create it.
69
74
 
70
75
  A few things to know:
71
76
 
72
77
  - `$` only opens the editor when it is the first character in the composer.
73
- - `/scratchpad` opens a plain-text scratchpad; pass `markdown` or `ruby` to pick another mode.
78
+ - `/scratchpad` opens a plain-text scratchpad; pass a language name or shortcut to select syntax highlighting. `/scratchpad help` lists the available choices.
74
79
  - Once a file or scratchpad opens, the composer becomes the editor.
75
80
  - Save or quit to return to normal chat.
76
81
  - If the file changed on disk while you were editing, Kward asks before overwriting it.
@@ -252,7 +257,7 @@ Emacs mode is for users who prefer classic Emacs-style non-modal editing. Save a
252
257
 
253
258
  Vibe mode is a modal editor built for Kward, inspired by classic Vi and Vim. If you already know Vim, you will feel at home here. Files open in normal mode, where keys run commands. Press `i`, `a`, `o`, or another insert command to type text, then press `Esc` to return to normal mode.
254
259
 
255
- It supports a compact but practical modal-editing set: counts, operators with motions, visual selections, visual block edits, marks, registers, macros, search, repeat (`.`), Ruby-aware navigation, and `:` commands. It is not a full Vim clone — there are no splits or ex-mode scripting — but it covers everyday keyboard editing inside the conversation.
260
+ It supports a compact but practical modal-editing set: counts, operators with motions, visual selections, multi-cursor and visual block edits, marks, registers, macros, search, repeat (`.`), Ruby-aware navigation, and `:` commands. It is not a full Vim clone — there are no splits or ex-mode scripting — but it covers everyday keyboard editing inside the conversation.
256
261
 
257
262
  The status line always shows the current mode (`NORMAL`, `INSERT`, `VISUAL`, `REPLACE`, or `:`) so you never lose track of where you are.
258
263
 
@@ -288,7 +293,7 @@ Use normal mode for movement, operators, marks, registers, macros, search, and c
288
293
  | `Ctrl+K` | Move up by indentation level |
289
294
  | `Ctrl+F` | Page down |
290
295
  | `Ctrl+B` | Page up |
291
- | `Ctrl+D` | Half page down |
296
+ | `Ctrl+D` | Select the next occurrence and enter insert mode |
292
297
  | `Ctrl+U` | Half page up |
293
298
  | `Ctrl+E` | Scroll down one line |
294
299
  | `Ctrl+Y` | Scroll up one line |
@@ -354,17 +359,20 @@ Use normal mode for movement, operators, marks, registers, macros, search, and c
354
359
 
355
360
  ### Visual mode
356
361
 
357
- Visual mode uses the same motion language as normal mode where practical. Start characterwise visual mode with `v`, linewise mode with `V`, or visual block mode with `Ctrl+V`.
362
+ Visual mode uses the same motion language as normal mode where practical. Arrow keys and plain `h`/`j`/`k`/`l` extend the selection. Start characterwise visual mode with `v`, linewise mode with `V`, or visual block mode with `Ctrl+V`.
358
363
 
359
364
  | Key | Action |
360
365
  | ----------------------- | ----------------------------------------------- |
361
366
  | `o` | Switch active end of visual selection |
367
+ | `Ctrl+h` / `Ctrl+l` | Outdent / indent selected lines |
368
+ | `Ctrl+j` / `Ctrl+k` | Move selected lines down / up |
362
369
  | `G` / `gg` / `N`motion | Extend visual selection with counts/motions |
363
370
  | `%`, `f`/`F`/`t`/`T` | Extend visual selection with advanced motions |
364
371
  | `iw` / `a(` / `ip` | Select visual text objects |
365
372
  | `>` / `<` | Indent / outdent selected lines |
366
373
  | `=` | Reindent selected lines |
367
- | `I` / `A` | Insert / append text across visual block lines |
374
+ | `I` / `A` | Insert cursors at the start / end of each selected line |
375
+ | `Ctrl+D` | Add the next occurrence of a characterwise selection |
368
376
  | `J` | Join selected lines |
369
377
  | `~` / `u` / `U` | Swapcase / lowercase / uppercase selection |
370
378
  | `/` / `?` / `n` / `N` | Extend visual selection with search |
@@ -388,7 +396,7 @@ Vibe insert mode also supports readline-style shortcuts for efficient editing wi
388
396
  | `Ctrl+E` | Move to end of line |
389
397
  | `Ctrl+B` | Move left |
390
398
  | `Ctrl+F` | Move right |
391
- | `Ctrl+D` | Delete character at cursor |
399
+ | `Ctrl+D` | Select the next occurrence |
392
400
  | `Ctrl+K` | Kill to end of line |
393
401
  | `Ctrl+U` | Kill to start of line |
394
402
  | `Ctrl+W` | Delete word before cursor |
@@ -416,7 +424,7 @@ Typing an opening bracket (`(`, `[`, `{`) or quote (`"`, `'`, `` ` ``) in visual
416
424
 
417
425
  ### Command mode
418
426
 
419
- Enter command mode with `:` from normal mode. Type a command and press `Enter`. Press `Esc` or `Ctrl+C` to cancel.
427
+ Enter command mode with `:` from normal mode. Type a command and press `Enter`. Press `Esc` or `Ctrl+C` to cancel. From visual mode, `:` starts the command with the selected line range (`'<,'>`), as in Vim.
420
428
 
421
429
  | Command | Action |
422
430
  | ------- | ------------------------------------------ |
@@ -426,6 +434,13 @@ Enter command mode with `:` from normal mode. Type a command and press `Enter`.
426
434
  | `:wq` | Save and quit |
427
435
  | `:x` | Save if changed, then quit |
428
436
  | `:N` | Go to line `N` |
437
+ | `:run` | Run the complete current supported editor buffer; inside a Markdown fence, run that block into its `<output>` field |
438
+ | `:run all` | Run every runnable Markdown fenced block sequentially into its `<output>` field |
439
+ | `:prompt instruction` | Ask the editor agent to update the buffer |
440
+ | `:s/a/b/g` | Substitute `a` with `b` |
441
+ | `:'<,'>s/a/b/g` | Substitute only across the visual selection |
442
+
443
+ Visual line ranges apply to `:s` and `:run`. For `:run`, select the body or complete fence of one Markdown code block with a runnable language, or place the cursor inside that block without making a selection; Kward runs that block and inserts or replaces a formatted `<output>` field without opening the output pane. `:run all` executes every runnable fenced block in document order, skips unlabeled or unsupported fences, continues after failures, and writes each runner error into that block's output field. An existing output field is searched for after the block until the next code fence, so inline fields are reformatted too. Without a matching output field, one is inserted directly below the block with one blank line. Other commands retain their normal save, navigation, file, and quit behavior.
429
444
 
430
445
  ### Vibe design notes
431
446
 
data/doc/files.md CHANGED
@@ -12,7 +12,7 @@ From an interactive Kward session, run:
12
12
  /files
13
13
  ```
14
14
 
15
- Kward opens the project file browser. Use the arrow keys or `j`/`k` to move through the tree, then press `Enter` on a file to open it in the integrated editor. Supported images (PNG, JPEG, GIF, and WebP) open as read-only inline previews when the terminal supports Kitty or iTerm2 image sequences.
15
+ Kward opens the project file browser. Use the arrow keys or `j`/`k` to move through the tree, then press `Enter` on a file to open it in the integrated editor. Supported images (PNG, JPEG, GIF, and WebP) open as read-only inline previews when the terminal supports Kitty or iTerm2 image sequences. Use `f` for a new file, `d` for a new directory, or `r` to rename the selected file or directory; type the single entry name in the prompt and press `Enter`.
16
16
 
17
17
  When you quit the editor or close an image preview, Kward returns to the file browser at the same position so you can keep browsing nearby files.
18
18
 
@@ -40,7 +40,11 @@ Outside Git, Kward scans the workspace directory and skips common noisy director
40
40
  | `/` | Start search |
41
41
  | `Backspace` | Delete the last search character |
42
42
  | `i` | Show or hide Git-ignored files |
43
- | `Esc` | Leave search; press again to close the browser |
43
+ | `f` | Create a file beneath the selected directory, or beside the selected file |
44
+ | `d` | Create a directory beneath the selected directory, or beside the selected file |
45
+ | `r` | Rename the selected file or directory; the prompt starts with its current name |
46
+ | `Backspace` | Start deletion confirmation for the selected file or directory |
47
+ | `Esc` | Leave search or name entry; cancel deletion; press again to close the browser |
44
48
  | `Q` | Close an image preview |
45
49
  | `+` / `-` | Zoom an image preview in / out |
46
50
  | `@` | Insert the selected file as an `@path` mention |
@@ -93,7 +97,7 @@ See [Integrated editor](editor.md) for editor modes, save/quit keys, search, sel
93
97
 
94
98
  Kward remembers the expanded folders, selected path, and Git-ignored file visibility for each workspace. The next time you open `/files` in the same project, it restores the browser close to where you left it.
95
99
 
96
- Search itself is temporary. Closing search returns to the normal tree, and closing the browser leaves your chat session intact.
100
+ Search itself is temporary. Closing search returns to the normal tree, and closing the browser leaves your chat session intact. Create and rename operations reject existing names rather than replacing them; name entry accepts only one file or directory name, not a path. Backspace requires confirmation before deleting. Non-empty directories display an additional warning and require a second confirmation before recursive deletion.
97
101
 
98
102
  ## Image previews
99
103
 
@@ -103,5 +107,5 @@ Image previews are read-only and replace the file-list overlay while leaving the
103
107
 
104
108
  - `/files` is only available in the interactive prompt.
105
109
  - It opens files inside the current workspace.
106
- - It is a focused project browser, not a full file manager: it does not rename, move, copy, or delete files.
110
+ - It is a focused project browser, not a full file manager: it does not move or copy files.
107
111
  - Ignored Git files are hidden by default when Git can provide the file list; press `i` in the tree view to show them.
@@ -7,6 +7,7 @@ This page gets you from install to a first useful chat.
7
7
  ## Requirements
8
8
 
9
9
  - Ruby 3.4 or newer.
10
+ - macOS or Linux. WSL is best effort; native Windows is not currently supported. See [Platform support](platform-support.md).
10
11
  - Credentials for one model provider. The easiest setup is `kward login` or `/login` inside Kward.
11
12
  - Bundler only if you run Kward from a source checkout.
12
13
 
@@ -96,6 +97,8 @@ Find where user authentication is implemented and summarize the flow.
96
97
 
97
98
  Kward can read files, suggest edits, apply changes, and run commands from the workspace. Existing files must be read in the current conversation before Kward can edit them.
98
99
 
100
+ The composer footer highlights the two main discovery shortcuts: type `/` to browse commands and `@` to find and mention project files. If no model provider is connected, the startup screen points directly to `/login` and `/model` before you submit a prompt.
101
+
99
102
  ## Ask one question and exit
100
103
 
101
104
  For quick tasks, pass the prompt directly:
data/doc/pan.md CHANGED
@@ -8,39 +8,41 @@ Use it when you want to work from another browser or device on a trusted network
8
8
 
9
9
  Pan is a small local HTTP server, not a hosted service. The machine running Kward performs model requests, reads and edits workspace files, runs tools, and stores sessions.
10
10
 
11
- Pan requires HTTP Basic Auth. Add credentials to `~/.kward/config.json`:
11
+ Pan requires HTTP Basic Auth. Add a username and password to `~/.kward/config.json`:
12
12
 
13
13
  ```json
14
14
  {
15
15
  "pan_mode": {
16
- "host": "0.0.0.0",
17
- "port": 8765,
18
16
  "username": "kward",
19
17
  "password": "choose-a-long-private-password"
20
18
  }
21
19
  }
22
20
  ```
23
21
 
24
- The defaults are:
22
+ Pan listens on `127.0.0.1:8765` by default, so only browsers on the same machine can connect. Kward refuses to start Pan unless a username and password are available.
23
+
24
+ To keep the password out of `config.json`, omit `password` and provide it when starting Pan:
25
25
 
26
- - `host`: `0.0.0.0`, which listens on all network interfaces.
27
- - `port`: `8765`.
26
+ ```bash
27
+ KWARD_PAN_PASSWORD="choose-a-long-private-password" kward pan
28
+ ```
28
29
 
29
- Kward refuses to start Pan unless both `username` and `password` are configured. The password is stored as plaintext in your config file, so do not reuse an important password or share the file.
30
+ When stored in `config.json`, the password is plaintext. Do not reuse an important password or share the file. Environment variables avoid config-file storage but may still be visible to processes or shell-history tooling on your machine.
30
31
 
31
- For access from the same machine only, bind to loopback instead:
32
+ To use Pan from another device on a trusted LAN, explicitly listen on all interfaces:
32
33
 
33
34
  ```json
34
35
  {
35
36
  "pan_mode": {
36
- "host": "127.0.0.1",
37
+ "host": "0.0.0.0",
37
38
  "port": 8765,
38
- "username": "kward",
39
- "password": "choose-a-long-private-password"
39
+ "username": "kward"
40
40
  }
41
41
  }
42
42
  ```
43
43
 
44
+ Then start Pan with `KWARD_PAN_PASSWORD` or add the password to that configuration. Kward prints a plain-HTTP exposure warning whenever Pan binds to a non-loopback address.
45
+
44
46
  ## Start Pan
45
47
 
46
48
  Run Pan from the project it should control:
@@ -56,12 +58,14 @@ Or select the workspace explicitly:
56
58
  kward --working-directory ~/code/my-project pan
57
59
  ```
58
60
 
59
- Kward prints the listening URL, workspace, and initial session path. With the default LAN binding, it detects and prints the machine's routed LAN address when available. Open port `8765` at that address, for example:
61
+ Kward prints the listening URL, workspace, and initial session path. With the default loopback binding, open:
60
62
 
61
63
  ```text
62
- http://192.168.1.25:8765/
64
+ http://127.0.0.1:8765/
63
65
  ```
64
66
 
67
+ With an explicit `0.0.0.0` LAN binding, Kward detects and prints the machine's routed LAN address when available, such as `http://192.168.1.25:8765/`.
68
+
65
69
  Your browser asks for the configured Basic Auth username and password.
66
70
 
67
71
  Press `Ctrl+C` in the server terminal to stop Pan. Closing a browser tab does not stop the server or an active turn.
@@ -142,8 +146,8 @@ Pan exposes powerful agent tools through ordinary HTTP. Basic Auth protects ever
142
146
 
143
147
  Use these precautions:
144
148
 
145
- - Run it only on a network and machine you trust.
146
- - Prefer `127.0.0.1` when remote access is unnecessary.
149
+ - Keep the default `127.0.0.1` binding when remote access is unnecessary.
150
+ - Bind to `0.0.0.0` only on a network and machine you trust.
147
151
  - Do not expose the port directly to the public internet.
148
152
  - Do not put Pan behind a public tunnel unless you provide a properly secured TLS/authentication boundary and understand the risk.
149
153
  - Use a unique password and protect `config.json`.
@@ -0,0 +1,48 @@
1
+ # Platform support
2
+
3
+ Kward is a terminal application built around Ruby, PTYs, filesystem tools, and operating-system command boundaries. The core agent works across Unix-like systems, while a few terminal and sandbox features depend on the host platform.
4
+
5
+ ## Support matrix
6
+
7
+ | Platform | Support level | Notes |
8
+ | --- | --- | --- |
9
+ | macOS | Supported | Primary support for the interactive TUI, PTY handoff, editor, shell, Pan, RPC, and Seatbelt command sandboxing. |
10
+ | Linux | Supported | Interactive TUI, PTY handoff, editor, shell, Pan, and RPC are supported. Bubblewrap is required for OS-enforced command sandboxing. |
11
+ | WSL | Best effort | Core CLI behavior should work under a current WSL environment. Clipboard, browser launch, inline images, PTY controls, and host integration vary by terminal and Windows configuration. |
12
+ | Native Windows | Unsupported | Kward currently depends on Unix-style PTY and process behavior. Use WSL rather than a native Windows Ruby installation. |
13
+
14
+ Kward requires Ruby 3.4 or newer. CI exercises Ruby 3.4 and the current Ruby release on Linux. Releases are developed and used on macOS as well.
15
+
16
+ ## Terminal expectations
17
+
18
+ Use a modern UTF-8 terminal with ANSI control-sequence support. Basic chat works without optional graphics protocols. Some features depend on terminal capabilities:
19
+
20
+ - modified keys such as Shift+Return and Ctrl+Tab may be intercepted by the terminal;
21
+ - inline images require iTerm2 or a recognized Kitty-compatible terminal;
22
+ - full-screen child applications temporarily own the terminal through PTY handoff;
23
+ - Nerd Font project-file icons are opt-in because Kward cannot detect the configured font.
24
+
25
+ See [Interactive composer](composer.md) for keyboard fallbacks and [Embedded shell](shell.md) for PTY behavior.
26
+
27
+ ## Sandboxing
28
+
29
+ Command sandboxing is opt-in and platform-specific:
30
+
31
+ - macOS uses Seatbelt profiles;
32
+ - Linux uses Bubblewrap and requires a host configuration that permits unprivileged namespaces;
33
+ - WSL support depends on the Linux distribution and host namespace policy;
34
+ - native Windows has no supported command sandbox backend.
35
+
36
+ When Kward cannot enforce a requested non-off sandbox mode, it fails closed rather than silently running the model-requested command without that boundary. See [Command sandboxing](sandboxing.md) for setup and exact limits.
37
+
38
+ ## Reporting a platform problem
39
+
40
+ Run these commands first:
41
+
42
+ ```bash
43
+ ruby --version
44
+ kward --version
45
+ kward doctor
46
+ ```
47
+
48
+ When opening a bug report, include the operating system, terminal, Ruby version, Kward version, and the smallest reproduction. Remove credentials, private paths, repository content, and sensitive command output before posting logs.
data/doc/security.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Kward can read code, edit files, run commands, call model and search providers, and load local extensions. That makes it useful, but it also means you should treat it like a developer tool running with your account—not like a sandbox.
4
4
 
5
- This guide explains the trust boundaries and gives you a safe way to start work in an unfamiliar repository.
5
+ This guide explains the trust boundaries and gives you a safe way to start work in an unfamiliar repository. Report suspected vulnerabilities privately through the [security policy](https://github.com/kaiwood/kward/blob/main/SECURITY.md).
6
6
 
7
7
  ## The short version
8
8
 
@@ -56,7 +56,8 @@ Kward's built-in file tools normally resolve paths inside the active workspace.
56
56
 
57
57
  These protections reduce accidental edits. They do not contain the whole process:
58
58
 
59
- - With `sandbox.mode: off` (the default), `run_shell_command`, `!command`, `/capture`, `/shell`, and `/pty` run with your user permissions.
59
+ - With `sandbox.mode: off` (the default), `run_shell_command`, `!command`, `/capture`, `/shell`, `/pty`, and editor buffer runners run with your user permissions.
60
+ - Editor buffer runners are user-directed and execute the current in-memory buffer, including normal files and scratchpads, through the configured `editor.runners` binary without a shell. They are not covered by the command sandbox.
60
61
  - A non-off [command sandbox](sandboxing.md) restricts only model-requested `run_shell_command` workers and their descendants. It does not cover `!command`, `/capture`, `/shell`, or `/pty`, including commands that the transient `?` shell assistant runs through the user's persistent `/shell` process.
61
62
  - External `/shell` commands, `!command`, and `/pty` receive an interactive PTY. Kward forwards a conservative set of line-oriented controls into the inline region, then grants full-terminal passthrough when a child emits screen-oriented or unknown controls. Full passthrough bypasses transcript control-sequence sanitization, so run only commands you trust with terminal access. `capture <command>` and `/capture <command>` sanitize their captured output.
62
63
  - Plugins, command hooks, and MCP servers are local processes with the same general operating-system access.
data/doc/shell.md CHANGED
@@ -23,13 +23,12 @@ The command runs from the active workspace root and begins in an inline PTY regi
23
23
 
24
24
  When an inline command exits without reading input, safe output is mirrored into the transient transcript view so a repaint cannot hide it. Carriage-return and horizontal-cursor progress redraws are reduced to their final visible lines, while an unterminated synchronized-output update is closed before Kward redraws. If the child reads input, Kward retains only output captured before the first forwarded input byte; this prevents echoed passwords, OTPs, or other input from entering tab state. Output from one-off commands is never added to the AI conversation or sent to the model.
25
25
 
26
- Shell output can leave transient text in the transcript area. **After the command finishes, press Ctrl+L to redraw the durable conversation and clear that transient `!command` output.** While an interactive command is still running, the composer remains frozen and keyboard input—including Ctrl+L and Kward's tab shortcuts—belongs to the child process.
26
+ Shell output can leave transient text in the transcript area. **After the command finishes, press Ctrl+L to redraw the durable conversation and clear that transient `!command` output.** While an interactive command owns the terminal, the composer remains frozen and ordinary keyboard input belongs to the child process. Kward's tab shortcuts are intercepted separately; switching tabs detaches the command and lets it continue in the originating tab's bounded background state.
27
27
 
28
- Configured `ekwsh.yml` aliases also work after `!`:
28
+ Configured `kwshrc` aliases also work after `!`:
29
29
 
30
- ```yaml
31
- aliases:
32
- glog: "git log --decorate --stat --graph"
30
+ ```sh
31
+ alias glog='git log --decorate --stat --graph'
33
32
  ```
34
33
 
35
34
  ```text
@@ -38,9 +37,8 @@ aliases:
38
37
 
39
38
  An alias that resolves to `kward edit <filename>` opens Kward's integrated editor in the current session instead of starting a nested Kward process:
40
39
 
41
- ```yaml
42
- aliases:
43
- vibe: "kward edit"
40
+ ```sh
41
+ alias vibe='kward edit'
44
42
  ```
45
43
 
46
44
  ```text
@@ -112,6 +110,8 @@ If you explicitly ask the assistant to change shell state, it can use the active
112
110
 
113
111
  For a suggestion or prepared command, the assistant uses `prepare_shell_command`. The command is placed in the shell composer but is not run until you press `Enter`. Running a command directly and preparing one are deliberately separate actions.
114
112
 
113
+ If you explicitly ask it to open an existing workspace file, the assistant uses `open_editor` to open Kward's integrated editor. Opening the editor does not modify or save the file.
114
+
115
115
  The shell assistant cannot safely run commands that require terminal input. Ask it to prepare those commands instead. The local `/shell` session keeps one interactive shell process alive, so directory changes, variables, functions, aliases, and other shell state persist between commands. The one-off `!command` and `/capture` workflows remain separate. SSH remains available through the normal interactive PTY handoff, but shell-agent prompting resumes after that SSH session exits.
116
116
 
117
117
  ## Interactive and captured commands
@@ -131,13 +131,13 @@ Use `capture` inside `/shell` when you want ordinary, readable output in Kward's
131
131
 
132
132
  ```sh
133
133
  capture git status --short
134
- capture bundle exec ruby -Itest test/test_ekwsh.rb
134
+ capture bundle exec ruby -Itest test/test_kwsh.rb
135
135
  ```
136
136
 
137
- An `ekwsh` `capture` command:
137
+ An `kwsh` `capture` command:
138
138
 
139
139
  - does not receive keyboard input,
140
- - uses the timeout and output-size limit from `ekwsh.yml`,
140
+ - uses kwsh's built-in timeout and output-size limits,
141
141
  - preserves safe color and styling,
142
142
  - strips controls that could corrupt Kward's TUI,
143
143
  - can be cancelled with Ctrl+C.
@@ -163,9 +163,9 @@ Each Kward tab owns its `/shell` state. Switching away and back restores that ta
163
163
  - runtime aliases,
164
164
  - shell prompt and transcript view.
165
165
 
166
- Shell commands use a separate, workspace-scoped history rather than the normal chat-prompt history. Configure its size with `history_limit` in `ekwsh.yml`.
166
+ Shell commands use a separate, workspace-scoped history rather than the normal chat-prompt history. The shell-history limit is a built-in kwsh default.
167
167
 
168
- Kward's tab shortcuts work at the shell prompt and while a captured command is running. During an interactive command, the child owns every key; exit or interrupt it before switching Kward tabs. Bounded output from shell-agent `?` turns is also retained in the tab's transient runtime view, so it is restored when you switch away and back without being added to session history. Ctrl+L clears this transient shell and shell-agent output.
168
+ Kward's tab shortcuts work at the shell prompt and while a shell command is running. Switching tabs detaches the running command instead of interrupting it; bounded output and completion state remain owned by the originating tab and are restored when you return. While detached, the command no longer receives terminal input. Explicit cancellation or shutdown still terminates detached work. Bounded output from shell-agent `?` turns is also retained in the tab's transient runtime view, so it is restored when you switch away and back without being added to session history. Ctrl+L clears this transient shell and shell-agent output.
169
169
 
170
170
  ## Completion
171
171
 
@@ -210,6 +210,7 @@ The persistent `/shell` process handles these commands in-session so their state
210
210
  | `cd [dir]` | Change the shell directory. Supports `cd`, `cd -`, and relative paths. |
211
211
  | `pwd` | Print the shell directory. |
212
212
  | `export KEY[=value]` | Set an environment variable. `export` and `export -p` list variables. |
213
+ | `source <file>` / `. <file>` | Parse and apply aliases and exports from an rc file immediately. |
213
214
  | `unset KEY` | Remove an environment variable. |
214
215
  | `alias [name]` | List, inspect, or create aliases. |
215
216
  | `unalias name` / `unalias -a` | Remove aliases. |
@@ -220,39 +221,56 @@ The persistent `/shell` process handles these commands in-session so their state
220
221
 
221
222
  Built-ins take precedence over aliases and executables.
222
223
 
223
- ## Configure ekwsh
224
+ ## Configure kwsh
224
225
 
225
- Global shell configuration lives at:
226
+ Global shell configuration lives in these optional rc files, loaded in order:
226
227
 
227
228
  ```text
228
- ~/.kward/ekwsh.yml
229
+ ~/.kward/kwshrc
230
+ ~/.kwshrc
229
231
  ```
230
232
 
231
- When `KWARD_CONFIG_PATH` selects another main config file, Kward reads `ekwsh.yml` from the same directory.
233
+ When `KWARD_CONFIG_PATH` selects another main config file, Kward reads the first file beside that config file instead. The later file overrides earlier aliases and exported variables with the same names. The rc format currently supports declarative `alias`, `export`, and `source` directives:
232
234
 
233
- A practical configuration might look like this:
235
+ ```sh
236
+ alias ll='ls -la'
237
+ alias gs="git status --short"
238
+ export BUNDLE_WITHOUT=production
239
+ export PATH="$HOME/bin:$PATH"
240
+ source ~/.kward/kwsh-aliases
241
+ ```
234
242
 
235
- ```yaml
236
- shell: /bin/sh
237
- timeout_seconds: 300
238
- max_output_bytes: 1048576
239
- history_limit: 1000
243
+ `source` reads another rc file without executing it; relative paths in rc-file directives are resolved from the file containing the directive. When entered as a `/shell` builtin, the path is resolved from the current shell directory and its aliases and exports are applied immediately, without restarting Kward. Unsupported shell scripting is ignored for now.
240
244
 
241
- env:
242
- FORCE_COLOR: "1"
243
- BUNDLE_WITHOUT: "production"
244
- RAILS_ENV: "test"
245
+ The transient shell assistant normally follows the active conversation's model and reasoning effort. Configure it in the main JSON file:
245
246
 
246
- aliases:
247
- ll: "ls -la"
248
- gs: "git status --short"
249
- gd: "git diff --color=always"
250
- glog: "git log --decorate --stat --graph"
251
- be: "bundle exec"
252
- t: "bundle exec ruby -Itest"
247
+ ```json
248
+ {
249
+ "shell": {
250
+ "agent": {
251
+ "provider": "openrouter",
252
+ "model": "openai/gpt-5.6-sol",
253
+ "reasoning_effort": "none"
254
+ }
255
+ }
256
+ }
253
257
  ```
254
258
 
255
- ### Settings
259
+ The optional `provider` uses the lowercase configuration IDs listed in [Model providers](providers.md). When omitted, the shell assistant follows the active conversation. If a provider is explicitly configured without a model or reasoning effort, Kward uses that provider's defaults instead of inheriting the active conversation's values.
260
+
261
+ Override those settings with environment variables:
262
+
263
+ ```sh
264
+ export KWSH_PROVIDER="openrouter"
265
+ export KWSH_MODE="openai/gpt-5.6-sol"
266
+ export KWSH_REASONING="none"
267
+ ```
268
+
269
+ Environment variables take precedence over the JSON settings, and empty values are ignored.
270
+
271
+ ### Runtime defaults
272
+
273
+ These runtime settings are built into kwsh and are not configurable through rc files:
256
274
 
257
275
  | Setting | Default | What it does |
258
276
  | --- | --- | --- |
@@ -265,14 +283,14 @@ Invalid or relative `shell` paths fall back to `/bin/sh`. These timeout and outp
265
283
 
266
284
  ### Environment
267
285
 
268
- Configured `env` values are applied when `/shell` starts. Keys must be valid environment-variable names; nil values and invalid keys are ignored, and other values are converted to strings.
286
+ `export` values from rc files are applied when `/shell` starts and are also available to leading-`!` commands. Keys must be valid environment-variable names; invalid keys are ignored. Values support shell quoting and simple `$VAR`/`${VAR}` expansion.
269
287
 
270
288
  Kward also supplies conservative terminal defaults:
271
289
 
272
290
  ```sh
273
- CLICOLOR=1
274
- COLORTERM=truecolor
275
- TERM=xterm-256color # only when TERM is missing or dumb
291
+ export CLICOLOR=1
292
+ export COLORTERM=truecolor
293
+ export TERM=xterm-256color # only when TERM is missing or dumb
276
294
  ```
277
295
 
278
296
  It does not force color. Set `FORCE_COLOR`, `CLICOLOR_FORCE`, or a command-specific option such as `--color=always` when needed.
@@ -283,18 +301,17 @@ When rbenv is available, Kward adds its shims and bin directories to `PATH` and
283
301
 
284
302
  Aliases replace the first command word once and append any remaining arguments:
285
303
 
286
- ```yaml
287
- aliases:
288
- ll: "ls -la"
289
- t: "bundle exec ruby -Itest"
304
+ ```sh
305
+ alias ll='ls -la'
306
+ alias t='bundle exec ruby -Itest'
290
307
  ```
291
308
 
292
309
  ```sh
293
310
  ll lib
294
311
  # runs: ls -la lib
295
312
 
296
- t test/test_ekwsh.rb
297
- # runs: bundle exec ruby -Itest test/test_ekwsh.rb
313
+ t test/test_kwsh.rb
314
+ # runs: bundle exec ruby -Itest test/test_kwsh.rb
298
315
  ```
299
316
 
300
317
  Configured aliases work inside `/shell` and after `!`. Aliases created with the `alias` built-in belong only to the current `/shell` session and are not shared with one-shot `!command` input.
@@ -10,14 +10,24 @@ This page covers common issues and how to diagnose them. When something is not w
10
10
  kward doctor
11
11
  ```
12
12
 
13
- It checks that your config file is readable and valid JSON, that the config and session directories are writable, that the workspace exists, which provider and model are active, and which credentials are configured. Use it as the first diagnostic step for any unexpected behavior.
13
+ It checks that your config file is readable and valid JSON, that the config and session directories are writable, that the workspace exists, which provider and model are active, and which credentials are configured. Core check failures produce a nonzero exit status, so the command can also guard setup scripts. Optional features such as Pan are reported separately and do not make an otherwise healthy setup fail.
14
14
 
15
- `kward auth status` gives a focused view of credentials only, also without printing secrets:
15
+ `kward auth status` gives a focused view of configured credentials only, also without printing secrets:
16
16
 
17
17
  ```bash
18
18
  kward auth status
19
19
  ```
20
20
 
21
+ Use `kward auth status --all` when you also want to see every unconfigured provider.
22
+
23
+ Kward keeps normal command failures concise. To include a Ruby backtrace while diagnosing an unexpected failure, rerun the command with debug errors enabled:
24
+
25
+ ```bash
26
+ KWARD_DEBUG=1 kward "Repeat the failing task"
27
+ ```
28
+
29
+ Backtraces can include local paths and implementation details. Review them before sharing them publicly.
30
+
21
31
  ## Authentication errors and token expiration
22
32
 
23
33
  OAuth tokens expire. Kward refreshes access tokens automatically when a refresh token is available, but if the refresh token is missing or expired, requests fail with a provider-specific error:
data/doc/usage.md CHANGED
@@ -66,7 +66,7 @@ Inside interactive mode, ask Kward to run a command:
66
66
  Run the focused test for the CLI status command.
67
67
  ```
68
68
 
69
- Or run an interactive PTY command yourself from the composer by prefixing it with `!`. Aliases configured in `ekwsh.yml` are expanded here too:
69
+ Or run an interactive PTY command yourself from the composer by prefixing it with `!`. Aliases configured in `kwshrc` are expanded here too:
70
70
 
71
71
  ```text
72
72
  !git status --short
@@ -78,7 +78,7 @@ For several commands, enter the embedded Kward shell:
78
78
  /shell
79
79
  ```
80
80
 
81
- `/shell` opens `ekwsh`, a Kward-native command mode with one persistent local shell process. It preserves state such as the current directory, environment variables, functions, and aliases between commands. Prefix a line with `?` inside `/shell` to ask a transient shell assistant about the latest output, execute an explicit state change, or prepare a command without running it. External commands receive an interactive PTY by default, so `git log`, `less`, Vim, SSH, and REPLs work without a prefix. Use `capture <command>` inside `/shell` or `/capture <command>` from the normal composer for bounded, transcript-friendly output. See [Embedded shell](shell.md) for built-ins, completion, configuration, ANSI handling, PTY passthrough, and limitations.
81
+ `/shell` opens `kwsh`, a Kward-native command mode with one persistent local shell process. It preserves state such as the current directory, environment variables, functions, and aliases between commands. Prefix a line with `?` inside `/shell` to ask a transient shell assistant about the latest output, execute an explicit state change, or prepare a command without running it. External commands receive an interactive PTY by default, so `git log`, `less`, Vim, SSH, and REPLs work without a prefix. Use `capture <command>` inside `/shell` or `/capture <command>` from the normal composer for bounded, transcript-friendly output. See [Embedded shell](shell.md) for built-ins, completion, configuration, ANSI handling, PTY passthrough, and limitations.
82
82
 
83
83
  ## Shell commands
84
84
 
@@ -160,7 +160,7 @@ Slash commands run local actions in the current session. Most do not send a prom
160
160
  | `/skill <name>` | activate a configured skill explicitly for the current session. |
161
161
  | `/stats [range]` | summarize enabled local telemetry. |
162
162
  | `/hooks ...` | inspect, diagnose, trust, or untrust lifecycle hooks. |
163
- | `/scratchpad [text|markdown|ruby]` | open an unsaved editor buffer. |
163
+ | `/scratchpad [language|help]` | open an unsaved, syntax-highlighted editor buffer; `/scratchpad` alone opens plain text. |
164
164
  | `/redraw` | fix terminal drawing after resize or glitches. |
165
165
  | `/reload` | reload installed plugins. |
166
166
  | `/exit` | leave Kward. |
@@ -263,13 +263,13 @@ This screenshot shows the broken layout. Find the likely CSS issue.
263
263
 
264
264
  ## Pan mode
265
265
 
266
- Pan mode starts a mobile-friendly LAN web UI:
266
+ Pan mode starts a mobile-friendly local web UI:
267
267
 
268
268
  ```bash
269
269
  kward --working-directory ~/code/project pan
270
270
  ```
271
271
 
272
- Use it only on trusted networks. It exposes file, shell, web, and configured extension tools through a browser UI and requires credentials configured in `config.json`. Pan saves conversations to the normal workspace session store; its session drawer can create, resume, rename, and delete sessions. Session changes are disabled while turns are active or queued. See [Pan mode](pan.md) for setup, browser workflows, security, and limitations.
272
+ Pan binds to loopback by default. Exposing it to a trusted LAN requires an explicit host setting and prints a warning because Pan uses plain HTTP. It exposes file, shell, web, and configured extension tools through a browser UI and requires a configured username plus a config or environment password. Pan saves conversations to the normal workspace session store; its session drawer can create, resume, rename, and delete sessions. Session changes are disabled while turns are active or queued. See [Pan mode](pan.md) for setup, browser workflows, security, and limitations.
273
273
 
274
274
  ## RPC backend
275
275