kon-coding-agent 0.3.2__tar.gz → 0.3.3__tar.gz

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 (139) hide show
  1. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/AGENTS.md +2 -2
  2. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/CHANGELOG.md +0 -1
  3. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/PKG-INFO +11 -68
  4. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/README.md +10 -67
  5. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/docs/local-models.md +16 -2
  6. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/pyproject.toml +2 -1
  7. kon_coding_agent-0.3.3/src/kon/async_utils.py +40 -0
  8. kon_coding_agent-0.3.3/src/kon/builtin_skills/init/SKILL.md +73 -0
  9. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/config.py +35 -5
  10. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/context/skills.py +62 -0
  11. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/core/types.py +1 -0
  12. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/defaults/config.toml +9 -1
  13. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/events.py +0 -1
  14. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/base.py +53 -0
  15. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/models.py +3 -3
  16. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/oauth/openai.py +7 -2
  17. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/anthropic.py +9 -3
  18. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/openai_completions.py +8 -5
  19. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/loop.py +10 -1
  20. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/_tool_utils.py +21 -36
  21. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/bash.py +30 -25
  22. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/edit.py +1 -1
  23. kon_coding_agent-0.3.3/src/kon/tools/read.py +237 -0
  24. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/web_fetch.py +1 -1
  25. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/web_search.py +1 -1
  26. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools_manager.py +6 -14
  27. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/turn.py +31 -20
  28. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/app.py +87 -59
  29. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/chat.py +2 -0
  30. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/commands.py +5 -9
  31. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/input.py +19 -3
  32. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/session_ui.py +4 -1
  33. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/widgets.py +18 -14
  34. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/conftest.py +0 -9
  35. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/context/test_skills.py +59 -0
  36. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/llm/test_anthropic_provider.py +28 -0
  37. kon_coding_agent-0.3.3/tests/llm/test_openai_oauth.py +14 -0
  38. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_agentic_loop.py +52 -4
  39. kon_coding_agent-0.3.3/tests/test_cli_auth_flags.py +26 -0
  40. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_config_binaries.py +1 -3
  41. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_config_migration.py +2 -0
  42. kon_coding_agent-0.3.3/tests/test_handoff_link_interrupt.py +74 -0
  43. kon_coding_agent-0.3.3/tests/test_local_auth_config.py +67 -0
  44. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_openai_compat.py +48 -1
  45. kon_coding_agent-0.3.3/tests/test_tools_manager.py +18 -0
  46. kon_coding_agent-0.3.3/tests/tools/test_read.py +180 -0
  47. kon_coding_agent-0.3.3/tests/tools/test_subprocess_cancellation.py +87 -0
  48. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/ui/test_input_paste.py +21 -0
  49. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/ui/test_status_line.py +0 -12
  50. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/uv.lock +28 -1
  51. kon_coding_agent-0.3.2/src/kon/metrics.py +0 -37
  52. kon_coding_agent-0.3.2/src/kon/tools/read.py +0 -136
  53. kon_coding_agent-0.3.2/tests/test_metrics.py +0 -50
  54. kon_coding_agent-0.3.2/tests/tools/test_read.py +0 -80
  55. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/.gitignore +0 -0
  56. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/.kon/skills/kon-release-publish/SKILL.md +0 -0
  57. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/.kon/skills/kon-tmux-test/SKILL.md +0 -0
  58. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/.kon/skills/kon-tmux-test/run-e2e-tests.sh +0 -0
  59. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/.kon/skills/kon-tmux-test/setup-test-project.sh +0 -0
  60. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/.python-version +0 -0
  61. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/LICENSE +0 -0
  62. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/docs/architecture-review.md +0 -0
  63. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/docs/images/kon-screenshot.png +0 -0
  64. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/scripts/show_themes.py +0 -0
  65. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/__init__.py +0 -0
  66. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/context/__init__.py +0 -0
  67. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/context/_xml.py +0 -0
  68. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/context/agent_mds.py +0 -0
  69. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/context/git.py +0 -0
  70. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/context/loader.py +0 -0
  71. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/core/__init__.py +0 -0
  72. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/core/compaction.py +0 -0
  73. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/core/handoff.py +0 -0
  74. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/defaults/__init__.py +0 -0
  75. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/__init__.py +0 -0
  76. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/oauth/__init__.py +0 -0
  77. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/oauth/copilot.py +0 -0
  78. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/__init__.py +0 -0
  79. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/azure_ai_foundry.py +0 -0
  80. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/copilot.py +0 -0
  81. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/copilot_anthropic.py +0 -0
  82. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/github_copilot_headers.py +0 -0
  83. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/mock.py +0 -0
  84. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/openai_codex_responses.py +0 -0
  85. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/openai_compat.py +0 -0
  86. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/openai_responses.py +0 -0
  87. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/llm/providers/sanitize.py +0 -0
  88. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/permissions.py +0 -0
  89. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/py.typed +0 -0
  90. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/session.py +0 -0
  91. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/themes.py +0 -0
  92. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/__init__.py +0 -0
  93. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/_read_image.py +0 -0
  94. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/base.py +0 -0
  95. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/find.py +0 -0
  96. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/grep.py +0 -0
  97. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/tools/write.py +0 -0
  98. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/__init__.py +0 -0
  99. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/app_protocol.py +0 -0
  100. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/autocomplete.py +0 -0
  101. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/blocks.py +0 -0
  102. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/clipboard.py +0 -0
  103. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/export.py +0 -0
  104. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/floating_list.py +0 -0
  105. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/formatting.py +0 -0
  106. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/path_complete.py +0 -0
  107. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/prompt_history.py +0 -0
  108. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/selection_mode.py +0 -0
  109. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/ui/styles.py +0 -0
  110. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/src/kon/update_check.py +0 -0
  111. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/context/test_agents.py +0 -0
  112. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/llm/__init__.py +0 -0
  113. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/llm/test_azure_ai_foundry_provider.py +0 -0
  114. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/llm/test_mock_provider.py +0 -0
  115. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/llm/test_openai_codex_provider_errors.py +0 -0
  116. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_cli_provider_resolution.py +0 -0
  117. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_compaction.py +0 -0
  118. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_config_error_fallback.py +0 -0
  119. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_config_injection.py +0 -0
  120. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_handoff.py +0 -0
  121. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_launch_warnings.py +0 -0
  122. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_model_provider_resolution.py +0 -0
  123. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_permissions.py +0 -0
  124. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_session_persistence.py +0 -0
  125. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_session_resume.py +0 -0
  126. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_system_prompt.py +0 -0
  127. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_system_prompt_git_context.py +0 -0
  128. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_update_check.py +0 -0
  129. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/test_update_notice_behavior.py +0 -0
  130. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/tools/test_diff.py +0 -0
  131. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/tools/test_edit.py +0 -0
  132. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/tools/test_edit_display.py +0 -0
  133. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/tools/test_read_image.py +0 -0
  134. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/tools/test_read_image_integration.py +0 -0
  135. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/tools/test_write.py +0 -0
  136. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/ui/test_autocomplete.py +0 -0
  137. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/ui/test_floating_list.py +0 -0
  138. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/ui/test_input_handoff.py +0 -0
  139. {kon_coding_agent-0.3.2 → kon_coding_agent-0.3.3}/tests/ui/test_prompt_history.py +0 -0
@@ -7,7 +7,7 @@
7
7
 
8
8
  ## Testing
9
9
 
10
- - Use `uv run pytest` for testing in general; after edits/writes
10
+ - Use `uv run python -m pytest` for testing in general; after edits/writes
11
11
  - If the user asks for e2e tests then run the kon-tmux e2e test if available
12
12
 
13
13
  ## Committing code
@@ -17,5 +17,5 @@
17
17
 
18
18
  ## Pushing
19
19
 
20
- - If the user asks you to push code, run these first before doing so: `uv run ruff format .`, `uv run ruff check .`, `uv run pyright .` and `uv run pytest` in parallel (same tool call)
20
+ - If the user asks you to push code, run these first before doing so: `uv run ruff format .`, `uv run ruff check .`, `uv run python -m pyright .` and `uv run python -m pytest` in parallel (same tool call)
21
21
  - Only if these all pass without issues should you push otherwise report the warnings/errors back to user and ask for next steps
@@ -30,7 +30,6 @@ All notable changes to this project will be documented in this file.
30
30
  - Added tool permission controls with bash safety analysis - @Meltedd.
31
31
  - Added popular built-in themes.
32
32
  - Added tool previews in approval prompts.
33
- - Added run token throughput metrics.
34
33
 
35
34
  ### Changed
36
35
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kon-coding-agent
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: Minimal coding agent
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -167,7 +167,7 @@ Here is the full config shape:
167
167
 
168
168
  ```toml
169
169
  [meta]
170
- config_version = 3
170
+ config_version = 4
171
171
 
172
172
  [llm]
173
173
  default_provider = "openai-codex"
@@ -176,6 +176,10 @@ default_base_url = ""
176
176
  default_thinking_level = "high"
177
177
  tool_call_idle_timeout_seconds = 180
178
178
 
179
+ [llm.auth]
180
+ openai_compat = "auto"
181
+ anthropic_compat = "auto"
182
+
179
183
  [llm.system_prompt]
180
184
  git_context = true
181
185
  content = """You are an expert coding assistant called Kon.
@@ -248,8 +252,9 @@ Kon is built around a terminal UI that stays simple but practical.
248
252
  | --- | --- |
249
253
  | File reference | Type `@` to fuzzy-search files and folders in the current project |
250
254
  | Path completion | Press **Tab** to complete paths like `./`, `../`, `~`, quoted paths, and absolute paths |
251
- | Queued prompts | You can submit follow-up prompts while the agent is still running |
252
- | Queue limit | Up to **5** queued prompts |
255
+ | Queued prompts | Press **Enter** while the agent is running to queue a follow-up prompt |
256
+ | Steer queue | Press **Alt+Enter** to queue a steer message that is processed before normal queued prompts |
257
+ | Queue limit | Up to **5** normal queued prompts and **5** steer messages |
253
258
  | Model switching | Use `/model` to switch interactively |
254
259
  | Session browsing | Use `/resume` to browse prior sessions |
255
260
 
@@ -437,73 +442,12 @@ kon --provider openai --model some-model --api-key "$OPENAI_API_KEY"
437
442
 
438
443
  ### Local models
439
444
 
440
- Kon works well with local models served through an OpenAI-compatible endpoint.
441
-
442
- Example with `llama-server`:
443
-
444
- ```bash
445
- ./llama-server -m <models-dir>/GLM-4.7-Flash-GGUF/GLM-4.7-Flash-Q4_K_M.gguf \
446
- -n 8192 \
447
- -c 64000
448
-
449
- kon --model zai-org/glm-4.7-flash \
450
- --provider openai \
451
- --base-url http://localhost:8080/v1 \
452
- --api-key ""
453
- ```
445
+ Kon works well with local models served through an OpenAI-compatible endpoint. For one-off launches, you can force unauthenticated local behavior with `--openai-compat-auth none` or `--anthropic-compat-auth none`. To make that persistent across sessions, set `[llm.auth] openai_compat = "auto"|"none"` and/or `anthropic_compat = "auto"|"none"` in `~/.kon/config.toml`.
454
446
 
455
447
  More notes, tested models, and examples live in [docs/local-models.md](docs/local-models.md).
456
448
 
457
449
  ---
458
450
 
459
- ### Configuration
460
-
461
- Kon stores config at:
462
-
463
- ```text
464
- ~/.kon/config.toml
465
- ```
466
-
467
- It is created automatically on first run, and old schemas are migrated forward automatically when needed.
468
-
469
- Users are recommended to customize this config based on their model, workflow, safety preferences, and UI taste.
470
-
471
- Here is the full config shape:
472
-
473
- ```toml
474
- [meta]
475
- config_version = 3
476
-
477
- [llm]
478
- default_provider = "openai-codex"
479
- default_model = "gpt-5.4"
480
- default_base_url = ""
481
- default_thinking_level = "high"
482
- tool_call_idle_timeout_seconds = 180
483
-
484
- [llm.system_prompt]
485
- git_context = true
486
- content = """You are an expert coding assistant called Kon.
487
- ..."""
488
-
489
- [compaction]
490
- on_overflow = "continue"
491
- buffer_tokens = 20000
492
-
493
- [agent]
494
- max_turns = 500
495
- default_context_window = 200000
496
-
497
- [tools]
498
- extra = ["web_search", "web_fetch"]
499
-
500
- [ui]
501
- theme = "gruvbox-dark"
502
-
503
- [permissions]
504
- mode = "prompt"
505
- ```
506
-
507
451
  ### Permissions
508
452
 
509
453
  Kon supports two permission modes:
@@ -526,9 +470,8 @@ Kon depends on a few fast CLI tools for file discovery and search:
526
470
 
527
471
  - **[`fd`](https://github.com/sharkdp/fd)** - required for fast file discovery
528
472
  - **[`ripgrep`](https://github.com/BurntSushi/ripgrep)** - required for fast content search
529
- - **[`eza`](https://github.com/eza-community/eza)** - optional
530
473
 
531
- If `fd` or `rg` are missing, Kon can download them automatically. `eza` is optional and mainly useful for cleaner, `.gitignore`-aware directory listings.
474
+ If `fd` or `rg` are missing, Kon can download them automatically.
532
475
 
533
476
  ---
534
477
 
@@ -149,7 +149,7 @@ Here is the full config shape:
149
149
 
150
150
  ```toml
151
151
  [meta]
152
- config_version = 3
152
+ config_version = 4
153
153
 
154
154
  [llm]
155
155
  default_provider = "openai-codex"
@@ -158,6 +158,10 @@ default_base_url = ""
158
158
  default_thinking_level = "high"
159
159
  tool_call_idle_timeout_seconds = 180
160
160
 
161
+ [llm.auth]
162
+ openai_compat = "auto"
163
+ anthropic_compat = "auto"
164
+
161
165
  [llm.system_prompt]
162
166
  git_context = true
163
167
  content = """You are an expert coding assistant called Kon.
@@ -230,8 +234,9 @@ Kon is built around a terminal UI that stays simple but practical.
230
234
  | --- | --- |
231
235
  | File reference | Type `@` to fuzzy-search files and folders in the current project |
232
236
  | Path completion | Press **Tab** to complete paths like `./`, `../`, `~`, quoted paths, and absolute paths |
233
- | Queued prompts | You can submit follow-up prompts while the agent is still running |
234
- | Queue limit | Up to **5** queued prompts |
237
+ | Queued prompts | Press **Enter** while the agent is running to queue a follow-up prompt |
238
+ | Steer queue | Press **Alt+Enter** to queue a steer message that is processed before normal queued prompts |
239
+ | Queue limit | Up to **5** normal queued prompts and **5** steer messages |
235
240
  | Model switching | Use `/model` to switch interactively |
236
241
  | Session browsing | Use `/resume` to browse prior sessions |
237
242
 
@@ -419,73 +424,12 @@ kon --provider openai --model some-model --api-key "$OPENAI_API_KEY"
419
424
 
420
425
  ### Local models
421
426
 
422
- Kon works well with local models served through an OpenAI-compatible endpoint.
423
-
424
- Example with `llama-server`:
425
-
426
- ```bash
427
- ./llama-server -m <models-dir>/GLM-4.7-Flash-GGUF/GLM-4.7-Flash-Q4_K_M.gguf \
428
- -n 8192 \
429
- -c 64000
430
-
431
- kon --model zai-org/glm-4.7-flash \
432
- --provider openai \
433
- --base-url http://localhost:8080/v1 \
434
- --api-key ""
435
- ```
427
+ Kon works well with local models served through an OpenAI-compatible endpoint. For one-off launches, you can force unauthenticated local behavior with `--openai-compat-auth none` or `--anthropic-compat-auth none`. To make that persistent across sessions, set `[llm.auth] openai_compat = "auto"|"none"` and/or `anthropic_compat = "auto"|"none"` in `~/.kon/config.toml`.
436
428
 
437
429
  More notes, tested models, and examples live in [docs/local-models.md](docs/local-models.md).
438
430
 
439
431
  ---
440
432
 
441
- ### Configuration
442
-
443
- Kon stores config at:
444
-
445
- ```text
446
- ~/.kon/config.toml
447
- ```
448
-
449
- It is created automatically on first run, and old schemas are migrated forward automatically when needed.
450
-
451
- Users are recommended to customize this config based on their model, workflow, safety preferences, and UI taste.
452
-
453
- Here is the full config shape:
454
-
455
- ```toml
456
- [meta]
457
- config_version = 3
458
-
459
- [llm]
460
- default_provider = "openai-codex"
461
- default_model = "gpt-5.4"
462
- default_base_url = ""
463
- default_thinking_level = "high"
464
- tool_call_idle_timeout_seconds = 180
465
-
466
- [llm.system_prompt]
467
- git_context = true
468
- content = """You are an expert coding assistant called Kon.
469
- ..."""
470
-
471
- [compaction]
472
- on_overflow = "continue"
473
- buffer_tokens = 20000
474
-
475
- [agent]
476
- max_turns = 500
477
- default_context_window = 200000
478
-
479
- [tools]
480
- extra = ["web_search", "web_fetch"]
481
-
482
- [ui]
483
- theme = "gruvbox-dark"
484
-
485
- [permissions]
486
- mode = "prompt"
487
- ```
488
-
489
433
  ### Permissions
490
434
 
491
435
  Kon supports two permission modes:
@@ -508,9 +452,8 @@ Kon depends on a few fast CLI tools for file discovery and search:
508
452
 
509
453
  - **[`fd`](https://github.com/sharkdp/fd)** - required for fast file discovery
510
454
  - **[`ripgrep`](https://github.com/BurntSushi/ripgrep)** - required for fast content search
511
- - **[`eza`](https://github.com/eza-community/eza)** - optional
512
455
 
513
- If `fd` or `rg` are missing, Kon can download them automatically. `eza` is optional and mainly useful for cleaner, `.gitignore`-aware directory listings.
456
+ If `fd` or `rg` are missing, Kon can download them automatically.
514
457
 
515
458
  ---
516
459
 
@@ -20,9 +20,23 @@ Run a local model using llama-server with the following command:
20
20
  -c 65536
21
21
  ```
22
22
 
23
- Then start kon:
23
+ Then start Kon for a one-off local session:
24
24
 
25
25
  ```bash
26
- kon --model unsloth/Qwen3.5-9B-GGUF --provider openai --base-url http://localhost:5000/v1 --api-key ""
26
+ kon --model unsloth/Qwen3.5-9B-GGUF --provider openai \
27
+ --base-url http://localhost:5000/v1 \
28
+ --openai-compat-auth none
29
+ ```
30
+
31
+ If this is your default setup, put it in `~/.kon/config.toml` instead:
32
+
33
+ ```toml
34
+ [llm]
35
+ default_provider = "openai"
36
+ default_model = "unsloth/Qwen3.5-9B-GGUF"
37
+ default_base_url = "http://localhost:5000/v1"
38
+
39
+ [llm.auth]
40
+ openai_compat = "auto" # or "none" to always inject a placeholder key
27
41
  ```
28
42
 
@@ -14,7 +14,7 @@ default = true
14
14
 
15
15
  [project]
16
16
  name = "kon-coding-agent"
17
- version = "0.3.2"
17
+ version = "0.3.3"
18
18
  description = "Minimal coding agent"
19
19
  readme = "README.md"
20
20
  requires-python = ">=3.12"
@@ -36,6 +36,7 @@ dev = [
36
36
  "pyright>=1.1.408",
37
37
  "pytest>=9.0.2",
38
38
  "pytest-asyncio>=1.3.0",
39
+ "ruff>=0.15.8",
39
40
  "twine>=5.1.1",
40
41
  ]
41
42
 
@@ -0,0 +1,40 @@
1
+ import asyncio
2
+ from contextlib import suppress
3
+ from typing import Any
4
+
5
+
6
+ class OperationCancelledError(Exception):
7
+ pass
8
+
9
+
10
+ async def cancel_and_await(task: asyncio.Future[Any]) -> None:
11
+ if task.done():
12
+ return
13
+ task.cancel()
14
+ with suppress(asyncio.CancelledError):
15
+ await task
16
+
17
+
18
+ async def await_or_cancel[T](work: asyncio.Future[T], cancel_event: asyncio.Event | None) -> T:
19
+ if not cancel_event:
20
+ return await work
21
+
22
+ if cancel_event.is_set():
23
+ await cancel_and_await(work)
24
+ raise OperationCancelledError
25
+
26
+ cancel = asyncio.create_task(cancel_event.wait())
27
+ try:
28
+ done, pending = await asyncio.wait({work, cancel}, return_when=asyncio.FIRST_COMPLETED)
29
+
30
+ for task in pending:
31
+ await cancel_and_await(task)
32
+
33
+ if cancel in done and cancel_event.is_set():
34
+ if not work.done():
35
+ await cancel_and_await(work)
36
+ raise OperationCancelledError
37
+
38
+ return work.result()
39
+ finally:
40
+ await cancel_and_await(cancel)
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: init
3
+ description: Create or update AGENTS.md for this repository
4
+ register_cmd: true
5
+ cmd_info: Guided AGENTS.md setup
6
+ ---
7
+
8
+ Create or update `AGENTS.md` for this repository.
9
+
10
+ The goal is a compact instruction file that helps future Kon sessions avoid mistakes and ramp up quickly. Every line should answer: "Would an agent likely miss this without help?" If not, leave it out.
11
+
12
+ User-provided focus or constraints (honor these):
13
+ $ARGUMENTS
14
+
15
+ ## How to investigate
16
+
17
+ Read the highest-value sources first:
18
+ - `README*`, root manifests, workspace config, lockfiles
19
+ - build, test, lint, formatter, typecheck, and codegen config
20
+ - CI workflows and pre-commit / task runner config
21
+ - existing instruction files (`AGENTS.md`, `CLAUDE.md`, `.cursor/rules/`, `.cursorrules`, `.github/copilot-instructions.md`)
22
+ - repo-local Kon config and conventions
23
+
24
+ If architecture is still unclear after reading config and docs, inspect a small number of representative code files to find the real entrypoints, package boundaries, and execution flow. Prefer reading the files that explain how the system is wired together over random leaf files.
25
+
26
+ Prefer executable sources of truth over prose. If docs conflict with config or scripts, trust the executable source and only keep what you can verify.
27
+
28
+ ## What to extract
29
+
30
+ Look for the highest-signal facts for an agent working in this repo:
31
+ - exact developer commands, especially non-obvious ones
32
+ - how to run a single test, a single package, or a focused verification step
33
+ - required command order when it matters, such as `lint -> typecheck -> test`
34
+ - monorepo or multi-package boundaries, ownership of major directories, and the real app/library entrypoints
35
+ - framework or toolchain quirks: generated code, migrations, codegen, build artifacts, special env loading, dev servers, infra deploy flow
36
+ - repo-specific style or workflow conventions that differ from defaults
37
+ - testing quirks: fixtures, integration test prerequisites, snapshot workflows, required services, flaky or expensive suites
38
+ - important constraints from existing instruction files worth preserving
39
+
40
+ Good `AGENTS.md` content is usually hard-earned context that took reading multiple files to infer.
41
+
42
+ ## Questions
43
+
44
+ Only ask the user questions if the repo cannot answer something important. Use the question tool for one short batch at most.
45
+
46
+ Good questions:
47
+ - undocumented team conventions
48
+ - branch / PR / release expectations
49
+ - missing setup or test prerequisites that are known but not written down
50
+
51
+ Do not ask about anything the repo already makes clear.
52
+
53
+ ## Writing rules
54
+
55
+ Include only high-signal, repo-specific guidance such as:
56
+ - exact commands and shortcuts the agent would otherwise guess wrong
57
+ - architecture notes that are not obvious from filenames
58
+ - conventions that differ from language or framework defaults
59
+ - setup requirements, environment quirks, and operational gotchas
60
+ - references to existing instruction sources that matter
61
+
62
+ Exclude:
63
+ - generic software advice
64
+ - long tutorials or exhaustive file trees
65
+ - obvious language conventions
66
+ - speculative claims or anything you could not verify
67
+ - content better stored in another file referenced via Kon config or another instruction file
68
+
69
+ When in doubt, omit.
70
+
71
+ Prefer short sections and bullets. If the repo is simple, keep the file simple. If the repo is large, summarize the few structural facts that actually change how an agent should work.
72
+
73
+ If `AGENTS.md` already exists, improve it in place rather than rewriting blindly. Preserve verified useful guidance, delete fluff or stale claims, and reconcile it with the current codebase.
@@ -18,6 +18,7 @@ from .themes import ColorsConfig, get_theme, get_theme_ids
18
18
  CONFIG_DIR_NAME: str = ".kon"
19
19
 
20
20
  OnOverflowMode = Literal["continue", "pause"]
21
+ AuthMode = Literal["auto", "required", "none"]
21
22
 
22
23
 
23
24
  # =================================================================================================
@@ -63,6 +64,11 @@ class SystemPromptConfig(BaseModel):
63
64
  git_context: bool = False
64
65
 
65
66
 
67
+ class AuthConfig(BaseModel):
68
+ openai_compat: AuthMode = "auto"
69
+ anthropic_compat: AuthMode = "auto"
70
+
71
+
66
72
  class LLMConfig(BaseModel):
67
73
  default_provider: str
68
74
  default_model: str
@@ -70,6 +76,7 @@ class LLMConfig(BaseModel):
70
76
  default_thinking_level: str
71
77
  system_prompt: SystemPromptConfig
72
78
  tool_call_idle_timeout_seconds: float = 180
79
+ auth: AuthConfig = AuthConfig()
73
80
 
74
81
 
75
82
  class CompactionConfig(BaseModel):
@@ -120,10 +127,6 @@ class _BinariesConfig:
120
127
  def fd(self) -> bool:
121
128
  return "fd" in self._binaries
122
129
 
123
- @property
124
- def eza(self) -> bool:
125
- return "eza" in self._binaries
126
-
127
130
 
128
131
  class Config:
129
132
  def __init__(self, data: dict[str, Any]) -> None:
@@ -227,7 +230,7 @@ def consume_config_warnings() -> list[str]:
227
230
 
228
231
 
229
232
  def _detect_available_binaries() -> set[str]:
230
- binaries = {"rg", "fd", "eza"}
233
+ binaries = {"rg", "fd"}
231
234
  available = set()
232
235
  bin_dir = Path.home() / CONFIG_DIR_NAME / "bin"
233
236
 
@@ -286,6 +289,29 @@ def _migrate_v2_to_v3(data: dict[str, Any]) -> dict[str, Any]:
286
289
  return migrated
287
290
 
288
291
 
292
+ def _migrate_v3_to_v4(data: dict[str, Any]) -> dict[str, Any]:
293
+ migrated = Config._apply_legacy_key_shims(data)
294
+ llm = migrated.get("llm")
295
+ if not isinstance(llm, dict):
296
+ llm = {}
297
+ migrated["llm"] = llm
298
+
299
+ auth = llm.get("auth")
300
+ if not isinstance(auth, dict):
301
+ auth = {}
302
+ llm["auth"] = auth
303
+
304
+ auth.setdefault("openai_compat", "auto")
305
+ auth.setdefault("anthropic_compat", "auto")
306
+
307
+ meta = migrated.get("meta")
308
+ if not isinstance(meta, dict):
309
+ migrated["meta"] = {"config_version": 4}
310
+ else:
311
+ meta["config_version"] = 4
312
+ return migrated
313
+
314
+
289
315
  def _migrate_config_data(data: dict[str, Any]) -> tuple[dict[str, Any], int, int, bool]:
290
316
  original = deepcopy(data)
291
317
  current_version = _get_config_version(original)
@@ -304,6 +330,10 @@ def _migrate_config_data(data: dict[str, Any]) -> tuple[dict[str, Any], int, int
304
330
  migrated = _migrate_v2_to_v3(migrated)
305
331
  current_version = 3
306
332
  continue
333
+ if current_version == 3:
334
+ migrated = _migrate_v3_to_v4(migrated)
335
+ current_version = 4
336
+ continue
307
337
  break
308
338
 
309
339
  migrated_version = _get_config_version(migrated)
@@ -12,6 +12,7 @@ Discovery locations:
12
12
  import os
13
13
  import re
14
14
  from dataclasses import dataclass
15
+ from importlib import resources
15
16
  from pathlib import Path
16
17
  from typing import Any
17
18
 
@@ -47,6 +48,7 @@ class Skill:
47
48
  description: str
48
49
  register_cmd: bool = False
49
50
  cmd_info: str = ""
51
+ bundled: bool = False
50
52
 
51
53
 
52
54
  @dataclass
@@ -228,6 +230,66 @@ def load_skills(cwd: str | None = None) -> LoadSkillsResult:
228
230
  return LoadSkillsResult(skills=list(skill_map.values()), warnings=all_warnings)
229
231
 
230
232
 
233
+ def load_builtin_cmd_skills() -> LoadSkillsResult:
234
+ try:
235
+ builtin_resource = resources.files("kon").joinpath("builtin_skills")
236
+ with resources.as_file(builtin_resource) as builtin_root:
237
+ result = _load_skills_from_dir(builtin_root)
238
+ except Exception:
239
+ return LoadSkillsResult(skills=[], warnings=[])
240
+ return LoadSkillsResult(
241
+ skills=[
242
+ Skill(
243
+ path=skill.path,
244
+ name=skill.name,
245
+ description=skill.description,
246
+ register_cmd=skill.register_cmd,
247
+ cmd_info=skill.cmd_info,
248
+ bundled=True,
249
+ )
250
+ for skill in result.skills
251
+ ],
252
+ warnings=result.warnings,
253
+ )
254
+
255
+
256
+ def strip_frontmatter(content: str) -> str:
257
+ if not content.startswith("---"):
258
+ return content.strip()
259
+ end_match = re.search(r"\n---\s*\n", content[3:])
260
+ if not end_match:
261
+ return content.strip()
262
+ return content[end_match.end() + 3 :].strip()
263
+
264
+
265
+ def render_skill_prompt(skill: Skill, query: str) -> str:
266
+ try:
267
+ content = Path(skill.path).read_text(encoding="utf-8")
268
+ except Exception:
269
+ return _build_fallback_skill_prompt(skill.description, query)
270
+ template = strip_frontmatter(content)
271
+ rendered = template.replace("$ARGUMENTS", query)
272
+ return rendered.strip()
273
+
274
+
275
+ def _build_fallback_skill_prompt(description: str, query: str) -> str:
276
+ query = query.strip()
277
+ if not query:
278
+ return description
279
+ return f"{description}\n\n{query}"
280
+
281
+
282
+ def merge_registered_skills(primary: list[Skill], secondary: list[Skill]) -> list[Skill]:
283
+ seen = {skill.name for skill in primary}
284
+ merged = list(primary)
285
+ for skill in secondary:
286
+ if skill.name in seen:
287
+ continue
288
+ merged.append(skill)
289
+ seen.add(skill.name)
290
+ return merged
291
+
292
+
231
293
  def formatted_skills(skills: list[Skill]) -> str:
232
294
  if not skills:
233
295
  return ""
@@ -12,6 +12,7 @@ class StopReason(StrEnum):
12
12
  TOOL_USE = "tool_use"
13
13
  ERROR = "error"
14
14
  INTERRUPTED = "interrupted"
15
+ STEER = "steer"
15
16
 
16
17
 
17
18
  class Usage(BaseModel):
@@ -1,5 +1,5 @@
1
1
  [meta]
2
- config_version = 3
2
+ config_version = 4
3
3
 
4
4
  [llm]
5
5
  default_provider = "openai-codex" # "zhipu", "github-copilot", "openai-codex"
@@ -12,6 +12,14 @@ default_thinking_level = "high"
12
12
  # Helps prevent stalled tool executions from hanging the agent loop.
13
13
  tool_call_idle_timeout_seconds = 180
14
14
 
15
+ [llm.auth]
16
+ # Auth policy for OpenAI-compatible and Anthropic-compatible endpoints.
17
+ # "auto" injects a placeholder key for local/self-hosted endpoints when no key is set.
18
+ # "required" keeps strict API key requirements.
19
+ # "none" always injects a placeholder key for that protocol family.
20
+ openai_compat = "auto" # "auto", "required", or "none"
21
+ anthropic_compat = "auto" # "auto", "required", or "none"
22
+
15
23
  [llm.system_prompt]
16
24
  git_context = true
17
25
  content = """You are an expert coding assistant called Kon. You help users by reading, searching, executing commands, editing code, and writing new files.
@@ -41,7 +41,6 @@ class TurnEndEvent:
41
41
  assistant_message: AssistantMessage | None = None
42
42
  tool_results: list[ToolResultMessage] = field(default_factory=list)
43
43
  stop_reason: StopReason = StopReason.STOP
44
- generation_seconds: float | None = None
45
44
  tool_call_count: int = 0
46
45
 
47
46