lcode-cli 0.16.0__tar.gz → 0.17.0__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 (134) hide show
  1. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/CHANGELOG.md +23 -1
  2. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/PKG-INFO +5 -2
  3. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/README.md +4 -1
  4. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/commands.md +2 -1
  5. lcode_cli-0.17.0/docs/git.md +98 -0
  6. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/quickstart.md +1 -1
  7. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/usage.md +4 -0
  8. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/mkdocs.yml +1 -0
  9. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/pyproject.toml +1 -0
  10. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/__init__.py +1 -1
  11. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/agent.py +11 -1
  12. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/cli.py +21 -0
  13. lcode_cli-0.17.0/src/lcode/gitflow.py +640 -0
  14. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/repl.py +38 -3
  15. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/tools.py +6 -0
  16. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_backends.py +6 -1
  17. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_extensions.py +3 -3
  18. lcode_cli-0.17.0/tests/test_gitflow.py +260 -0
  19. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.editorconfig +0 -0
  20. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/CODEOWNERS +0 -0
  21. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  22. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  23. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  24. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/ISSUE_TEMPLATE/model_request.yml +0 -0
  25. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  26. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/dependabot.yml +0 -0
  27. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/workflows/ci.yml +0 -0
  28. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/workflows/docs.yml +0 -0
  29. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.github/workflows/release.yml +0 -0
  30. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.gitignore +0 -0
  31. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/.pre-commit-config.yaml +0 -0
  32. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/AGENTS.md +0 -0
  33. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/CODE_OF_CONDUCT.md +0 -0
  34. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/CONTRIBUTING.md +0 -0
  35. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/LICENSE +0 -0
  36. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/SECURITY.md +0 -0
  37. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/agents.md +0 -0
  38. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/assets/demo.svg +0 -0
  39. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/assets/extra.css +0 -0
  40. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/assets/logo.svg +0 -0
  41. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/assets/social-preview.png +0 -0
  42. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/bench.md +0 -0
  43. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/changelog.md +0 -0
  44. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/configuration.md +0 -0
  45. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/contributing.md +0 -0
  46. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/hooks.md +0 -0
  47. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/how-it-works.md +0 -0
  48. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/index.md +0 -0
  49. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/installation.md +0 -0
  50. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/lsp.md +0 -0
  51. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/mcp.md +0 -0
  52. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/memory.md +0 -0
  53. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/models.md +0 -0
  54. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/sandbox.md +0 -0
  55. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/search.md +0 -0
  56. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/servers.md +0 -0
  57. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/docs/troubleshooting.md +0 -0
  58. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/examples/README.md +0 -0
  59. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/examples/commands/review.md +0 -0
  60. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/examples/skills/commit-message/SKILL.md +0 -0
  61. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/examples/skills/commit-message/scripts/staged.sh +0 -0
  62. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/install.sh +0 -0
  63. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/overrides/main.html +0 -0
  64. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/scripts/record_demo.py +0 -0
  65. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/scripts/social-preview.html +0 -0
  66. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/__main__.py +0 -0
  67. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/backends.py +0 -0
  68. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/bench.py +0 -0
  69. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/bench_backend.py +0 -0
  70. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/catalog.py +0 -0
  71. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/checkpoints.py +0 -0
  72. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/codesearch.py +0 -0
  73. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/config.py +0 -0
  74. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/context.py +0 -0
  75. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/extensions.py +0 -0
  76. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/frontmatter.py +0 -0
  77. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/hardware.py +0 -0
  78. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/hooks.py +0 -0
  79. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/limits.py +0 -0
  80. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/lsp.py +0 -0
  81. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/__init__.py +0 -0
  82. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/auth.py +0 -0
  83. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/catalog.py +0 -0
  84. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/catalog.toml +0 -0
  85. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/client.py +0 -0
  86. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/commands.py +0 -0
  87. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/config.py +0 -0
  88. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/http.py +0 -0
  89. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/manager.py +0 -0
  90. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/protocol.py +0 -0
  91. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/server.py +0 -0
  92. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/mcp/stdio.py +0 -0
  93. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/memory.py +0 -0
  94. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/models.toml +0 -0
  95. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/ollama.py +0 -0
  96. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/permissions.py +0 -0
  97. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/planning.py +0 -0
  98. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/render.py +0 -0
  99. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/repomap.py +0 -0
  100. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/sandbox.py +0 -0
  101. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/servers/__init__.py +0 -0
  102. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/servers/encord.py +0 -0
  103. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/servers/valohai.py +0 -0
  104. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/sessions.py +0 -0
  105. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/subagents.py +0 -0
  106. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/vision.py +0 -0
  107. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/src/lcode/web.py +0 -0
  108. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/conftest.py +0 -0
  109. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/fake_lsp_server.py +0 -0
  110. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/fake_mcp_server.py +0 -0
  111. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_agent.py +0 -0
  112. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_bench.py +0 -0
  113. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_catalog.py +0 -0
  114. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_checkpoints.py +0 -0
  115. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_cli.py +0 -0
  116. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_codesearch.py +0 -0
  117. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_config.py +0 -0
  118. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_context.py +0 -0
  119. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_context_picker.py +0 -0
  120. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_hooks.py +0 -0
  121. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_lsp.py +0 -0
  122. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_mcp.py +0 -0
  123. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_memory.py +0 -0
  124. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_permissions.py +0 -0
  125. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_plan_mode.py +0 -0
  126. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_repomap.py +0 -0
  127. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_sandbox.py +0 -0
  128. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_servers.py +0 -0
  129. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_sessions.py +0 -0
  130. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_subagents.py +0 -0
  131. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_tools.py +0 -0
  132. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_vision.py +0 -0
  133. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/tests/test_web.py +0 -0
  134. {lcode_cli-0.16.0 → lcode_cli-0.17.0}/uv.lock +0 -0
@@ -6,6 +6,27 @@ All notable changes to lcode are documented here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.17.0] - 2026-10-06
10
+
11
+ ### Added
12
+
13
+ - `/commit` writes a commit message in the repository's style, from the diff, the conversation
14
+ and recent commits, and commits once you approve it. It commits what you staged, or every
15
+ change except files the model thinks are unrelated and files that may hold secrets.
16
+ - `/review [base]` reviews the uncommitted changes, or the branch against a base, and reports
17
+ findings with `path:line`. The model can read but not change anything during a review.
18
+ - `/pr [base]` pushes the branch and opens a GitHub pull request with `gh` after you approve the
19
+ title and description; commits made on `main` itself go to a new branch.
20
+ - A command of your own called `commit`, `review` or `pr` replaces the built-in one.
21
+ - `lcode --worktree [NAME]` (`-w`) runs the session in a git worktree on its own branch, so
22
+ several sessions can work on one repository at once. It's removed at the end if nothing
23
+ changed. See [Git workflow](https://nasser1941.github.io/lcode/git/).
24
+
25
+ ### Fixed
26
+
27
+ - With another model server, `/ctx` no longer says the model reloads: it changes how much of the
28
+ server's context window lcode uses.
29
+
9
30
  ## [0.16.0] - 2026-10-05
10
31
 
11
32
  ### Added
@@ -398,7 +419,8 @@ First public release.
398
419
  - `AGENTS.md` project instructions and `/init` to generate them.
399
420
  - One-line installer for Linux and macOS.
400
421
 
401
- [Unreleased]: https://github.com/nasser1941/lcode/compare/v0.16.0...HEAD
422
+ [Unreleased]: https://github.com/nasser1941/lcode/compare/v0.17.0...HEAD
423
+ [0.17.0]: https://github.com/nasser1941/lcode/compare/v0.16.0...v0.17.0
402
424
  [0.16.0]: https://github.com/nasser1941/lcode/compare/v0.15.0...v0.16.0
403
425
  [0.15.0]: https://github.com/nasser1941/lcode/compare/v0.14.0...v0.15.0
404
426
  [0.14.0]: https://github.com/nasser1941/lcode/compare/v0.13.0...v0.14.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: lcode-cli
3
- Version: 0.16.0
3
+ Version: 0.17.0
4
4
  Summary: A local-first terminal coding agent powered by open-weight models on your own GPU or Mac, via Ollama.
5
5
  Project-URL: Homepage, https://nasser1941.github.io/lcode/
6
6
  Project-URL: Documentation, https://nasser1941.github.io/lcode/
@@ -101,6 +101,9 @@ through [Ollama](https://ollama.com), and when it needs current information it c
101
101
  - **Remembers what matters.** Corrections, decisions and where things live carry over to the next
102
102
  session as short notes, saved by the model, by you (`/remember`) or by a quick check at the end
103
103
  of a session. Not whole conversations, and never secrets.
104
+ - **Git workflow.** `/commit` writes messages in your repository's style, `/review` checks the
105
+ changes with `file:line` findings, `/pr` opens the pull request, each after you approve it, and
106
+ `lcode --worktree` runs parallel sessions on one repository.
104
107
  - **Bring your own model.** Eight curated open-weight models, all tested end to end, or any Ollama model
105
108
  with tool calling. Or use LM Studio, llama.cpp, vLLM or MLX instead of Ollama.
106
109
  - **MCP servers, ready to go.** Connect Jira and Confluence, GitHub, AWS, Google Drive, Grafana,
@@ -208,8 +211,8 @@ fills up. Details: [How it works](https://nasser1941.github.io/lcode/how-it-work
208
211
 
209
212
  See the pinned [Roadmap issue](https://github.com/nasser1941/lcode/issues/10). Next up:
210
213
 
211
- - [Git workflow: /commit, /review, /pr and parallel worktrees](https://github.com/nasser1941/lcode/issues/50)
212
214
  - [Automation: JSON output, a Python API and a GitHub Action for self-hosted runners](https://github.com/nasser1941/lcode/issues/48)
215
+ - [Editor integration through the Agent Client Protocol](https://github.com/nasser1941/lcode/issues/49)
213
216
  - More models in the catalog, and test reports from your hardware ([report one](https://github.com/nasser1941/lcode/issues/new?template=model_request.yml))
214
217
 
215
218
  ## Contributing
@@ -65,6 +65,9 @@ through [Ollama](https://ollama.com), and when it needs current information it c
65
65
  - **Remembers what matters.** Corrections, decisions and where things live carry over to the next
66
66
  session as short notes, saved by the model, by you (`/remember`) or by a quick check at the end
67
67
  of a session. Not whole conversations, and never secrets.
68
+ - **Git workflow.** `/commit` writes messages in your repository's style, `/review` checks the
69
+ changes with `file:line` findings, `/pr` opens the pull request, each after you approve it, and
70
+ `lcode --worktree` runs parallel sessions on one repository.
68
71
  - **Bring your own model.** Eight curated open-weight models, all tested end to end, or any Ollama model
69
72
  with tool calling. Or use LM Studio, llama.cpp, vLLM or MLX instead of Ollama.
70
73
  - **MCP servers, ready to go.** Connect Jira and Confluence, GitHub, AWS, Google Drive, Grafana,
@@ -172,8 +175,8 @@ fills up. Details: [How it works](https://nasser1941.github.io/lcode/how-it-work
172
175
 
173
176
  See the pinned [Roadmap issue](https://github.com/nasser1941/lcode/issues/10). Next up:
174
177
 
175
- - [Git workflow: /commit, /review, /pr and parallel worktrees](https://github.com/nasser1941/lcode/issues/50)
176
178
  - [Automation: JSON output, a Python API and a GitHub Action for self-hosted runners](https://github.com/nasser1941/lcode/issues/48)
179
+ - [Editor integration through the Agent Client Protocol](https://github.com/nasser1941/lcode/issues/49)
177
180
  - More models in the catalog, and test reports from your hardware ([report one](https://github.com/nasser1941/lcode/issues/new?template=model_request.yml))
178
181
 
179
182
  ## Contributing
@@ -46,7 +46,8 @@ Report bugs first, with `path:line`, then missing tests. Don't change any files.
46
46
  | `~/.config/lcode/commands/<name>.md` | For every repository |
47
47
 
48
48
  The file name is the command's name. A repository's command overrides one of yours with the same
49
- name; built-in commands such as `/help` can't be replaced.
49
+ name. A command called `review`, `commit` or `pr` replaces lcode's [built-in one](git.md), so a team
50
+ can use its own checklist; other built-in commands such as `/help` can't be replaced.
50
51
 
51
52
  ## Skills
52
53
 
@@ -0,0 +1,98 @@
1
+ # Git workflow
2
+
3
+ The everyday git steps, without spelling them out each time:
4
+ - **`/commit`** writes a message in your repository's style;
5
+ - **`/review`** checks the changes before you commit or merge;
6
+ - **`/pr`** opens a pull request;
7
+ - **`lcode --worktree`** runs several sessions on one repository without them getting in each other's way.
8
+
9
+ lcode never commits, pushes or opens a pull request until you say yes, also in `yolo` mode.
10
+
11
+ ## /commit
12
+
13
+ ```text
14
+ ❯ /commit
15
+ ╭─ Commit message ───────────────────────────────────────────────╮
16
+ │ feat: add median() │
17
+ │ │
18
+ │ Add a median() function to stats.py and its tests. It raises │
19
+ │ ValueError on empty input, consistent with mean(). │
20
+ ╰────────────────────────────────────────────────────────────────╯
21
+ Files stats.py, test_stats.py
22
+ Left out (unrelated, the model thinks): debug.log
23
+ [y] commit · [e] edit the message · [n] cancel: y
24
+ ✓ Committed fecd803 feat: add median()
25
+ ```
26
+
27
+ - **What goes in.**
28
+ - If you staged files (`git add`), exactly those.
29
+ - Otherwise every changed and new file, except:
30
+ - files the model thinks are unrelated to the work, listed so you can see them;
31
+ - files that may hold secrets (`.env`, `*.pem`, keys, credentials and the like). These only go in when you stage them yourself.
32
+ - **The message.** It's written from the diff, from what the conversation knows about why you made the change, and from the repository's recent commits: their prefixes, tense, length and trailers. `/commit mention ticket ABC-12` adds your own notes.
33
+ - **Editing.** `e` opens the message in your editor (`$EDITOR`).
34
+ - **Hooks.** Your git hooks run as usual: a failing pre-commit hook stops the commit and shows why.
35
+
36
+ ## /review
37
+
38
+ | | Reviews |
39
+ |---|---|
40
+ | `/review` | The uncommitted changes if any tracked file changed; otherwise the branch's changes compared with the default branch (`main`) |
41
+ | `/review develop` | The branch, and any uncommitted changes, compared with `develop` |
42
+
43
+ The model reads the code around the changes where it needs to. During a review it can't change
44
+ files or run commands that change anything. It reports findings with `path:line`, the kind of
45
+ problem (bug, test, security or clarity), what's wrong and how to fix it, most important first:
46
+
47
+ ```text
48
+ stats.py:18 — bug
49
+ The even-length median is broken: for median([1, 3, 2, 4]) the old code returns 2.5, the new
50
+ code returns 3. Revert line 18 to (s[mid - 1] + s[mid]) / 2.
51
+
52
+ test_stats.py:13 — test
53
+ test_median() asserts median([1, 3, 2, 4]) == 2.5, so it fails with this change.
54
+ ```
55
+
56
+ Then ask it to fix what you agree with, in the same conversation.
57
+
58
+ **Your own checklist:** put review guidelines in `AGENTS.md` or in a [skill](commands.md#skills),
59
+ and the review follows them. To replace `/review` entirely, write a
60
+ [command](commands.md#commands) of your own called `review`. The same goes for `/commit` and `/pr`.
61
+
62
+ ## /pr
63
+
64
+ Pushes the branch and opens a GitHub pull request. It needs the [GitHub CLI](https://cli.github.com),
65
+ signed in with `gh auth login`.
66
+
67
+ - **Into which branch.** The default branch, or the one you name: `/pr develop`. Anything else you
68
+ type is a note for the description: `/pr develop link it to #12`.
69
+ - **Before you start.** Commit first: `/pr` stops while there are uncommitted changes.
70
+ - **Commits made on `main` itself** go to a new branch named after the change. Your local `main`
71
+ still has them, so reset it once the pull request is merged.
72
+ - **The title and description** are written from the commits, the diff and the conversation, and
73
+ follow the repository's pull request template if it has one. You see them before anything is
74
+ pushed: `y` to push and open, `e` to edit, `n` to stop.
75
+ - **A branch with an open pull request:** `/pr` offers to push the new commits instead.
76
+
77
+ ## Parallel sessions: lcode --worktree
78
+
79
+ ```bash
80
+ lcode --worktree fix-login # a session on a new branch fix-login, in a folder of its own
81
+ lcode -w # the same, with a generated name
82
+ ```
83
+
84
+ A [git worktree](https://git-scm.com/docs/git-worktree) is a second working folder of the same
85
+ repository, on its own branch. Sessions in different worktrees can edit, test and commit at the
86
+ same time without touching each other's files, or yours.
87
+
88
+ - **Where it starts.** The worktree starts from your current commit. Uncommitted changes in your
89
+ own folder don't come along.
90
+ - **Where it lives.** lcode keeps worktree folders in `~/.local/state/lcode/worktrees/` and prints
91
+ the path. They're outside the repository so the model can't mistake your folder for its own.
92
+ - **When the session ends.**
93
+ - If nothing changed (no commits and no uncommitted changes), the worktree and its branch are
94
+ removed.
95
+ - Otherwise it stays, and lcode tells you how to continue (`lcode --worktree fix-login` again),
96
+ merge it (`git merge fix-login`) or remove it.
97
+ - **What's separate.** Sessions (`/resume`, `lcode -c`) and [checkpoints](usage.md#undo-and-checkpoints)
98
+ belong to each worktree. [Memory notes](memory.md) are shared with the repository.
@@ -12,7 +12,7 @@ lcode
12
12
 
13
13
  ```text
14
14
  ╭──────────────────────────────────────────────╮
15
- │ lcode v0.16.0 — local coding agent │
15
+ │ lcode v0.17.0 — local coding agent │
16
16
  │ │
17
17
  │ model lcode-qwen3.6-35b │
18
18
  │ context 256K tokens │
@@ -20,6 +20,7 @@ lcode mcp [catalog|add|list] # connect MCP servers: Jira, GitHub, AWS, databases
20
20
  | `-r, --repo DIR` | Work in another directory |
21
21
  | `-c, --continue` | Continue the most recently used session in this directory |
22
22
  | `--resume [SESSION]` | Resume a saved session: pick from a list, or give its number, name or id |
23
+ | `-w, --worktree [NAME]` | Work in a [git worktree](git.md#parallel-sessions-lcode-worktree) of its own, on branch NAME; removed at the end if nothing changed |
23
24
  | `--plan` | Start in [plan mode](#plan-mode): agree on a plan before anything changes |
24
25
  | `--auto-edit` | Apply file edits without asking (commands still ask) |
25
26
  | `--yolo` | Never ask for permission |
@@ -74,6 +75,9 @@ reasoning is on.
74
75
  | `/mode [ask\|plan\|auto-edit\|yolo]` | Set the permission mode |
75
76
  | `/cd DIR` | Change the working directory |
76
77
  | `/todos` | Show the model's task list |
78
+ | `/commit [notes]` | [Commit](git.md#commit) the changes with a message in the repository's style, once you approve it |
79
+ | `/review [base]` | [Review](git.md#review) the uncommitted changes, or the branch against a base |
80
+ | `/pr [base] [notes]` | Push the branch and open a GitHub [pull request](git.md#pr), once you approve it |
77
81
  | `/exit` | Quit |
78
82
 
79
83
  ## What the model can do
@@ -95,6 +95,7 @@ nav:
95
95
  - Memory: memory.md
96
96
  - Subagents: agents.md
97
97
  - Commands and skills: commands.md
98
+ - Git workflow: git.md
98
99
  - Code intelligence: lsp.md
99
100
  - Repository map and code search: search.md
100
101
  - Models & context windows: models.md
@@ -84,6 +84,7 @@ ignore = [
84
84
  "src/lcode/codesearch.py" = ["E501"]
85
85
  "src/lcode/bench_backend.py" = ["E501"]
86
86
  "src/lcode/backends.py" = ["E501"]
87
+ "src/lcode/gitflow.py" = ["E501"]
87
88
 
88
89
  [tool.pytest.ini_options]
89
90
  testpaths = ["tests"]
@@ -1,3 +1,3 @@
1
1
  """lcode — a local-first terminal coding agent powered by open-weight models via Ollama."""
2
2
 
3
- __version__ = "0.16.0"
3
+ __version__ = "0.17.0"
@@ -130,7 +130,14 @@ def git_info(cwd: Path) -> str:
130
130
  return "not a git repository"
131
131
  changed = git("status", "--short").stdout.strip().splitlines()
132
132
  log = git("log", "--oneline", "-5").stdout.strip() or "(no commits)"
133
- return f"branch {branch.stdout.strip()}, {len(changed)} changed file(s)\nRecent commits:\n{log}"
133
+ dirs = git("rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir").stdout.split()
134
+ worktree = (
135
+ "\nThis folder is a git worktree, separate from the repository's main checkout: read, change and "
136
+ "commit files only here, with paths inside this folder."
137
+ if len(dirs) == 2 and dirs[0] != dirs[1]
138
+ else ""
139
+ )
140
+ return f"branch {branch.stdout.strip()}, {len(changed)} changed file(s){worktree}\nRecent commits:\n{log}"
134
141
  except (OSError, subprocess.TimeoutExpired):
135
142
  return "unknown"
136
143
 
@@ -242,6 +249,7 @@ class Agent:
242
249
  # Set on subagents (see lcode.subagents):
243
250
  self.allowed_tools: set[str] | None = None # None: every tool
244
251
  self.read_only = False # only read-only shell commands
252
+ self.no_changes = "" # set during a review: why nothing may change (read-only tools only)
245
253
  self.cancel: threading.Event | None = None # set from another thread to stop
246
254
  self.on_tool = None # called with (name, arguments) before each tool runs
247
255
  self.response = None # the streaming response, so another thread can abort it
@@ -931,4 +939,6 @@ class Agent:
931
939
  else:
932
940
  note = ""
933
941
  self.settings.context = tokens
942
+ if getattr(self.ollama, "kind", "ollama") != "ollama": # the server keeps its own window
943
+ return f"lcode now uses {format_tokens(tokens)} tokens of the context window{note}, and summarizes sooner."
934
944
  return f"Context window set to {format_tokens(tokens)} tokens{note}. The model reloads on the next request."
@@ -626,6 +626,17 @@ def cmd_chat(args) -> None:
626
626
  cwd = Path(args.repo).expanduser().resolve()
627
627
  if not cwd.is_dir():
628
628
  fail(f"not a directory: {cwd}")
629
+ worktree = None
630
+ if args.worktree is not None:
631
+ from lcode import gitflow
632
+
633
+ try:
634
+ worktree = gitflow.start_worktree(cwd, args.worktree)
635
+ except gitflow.GitError as e:
636
+ fail(f"--worktree: {e}")
637
+ cwd = worktree.cwd
638
+ state = "a new worktree" if worktree.created_branch else "the worktree"
639
+ console.print(f"[dim]Working in {state} {worktree.path}, on branch {escape(worktree.branch)}.[/]")
629
640
  ollama = connect(cfg)
630
641
  hw = detect()
631
642
  check_ollama(ollama, hw)
@@ -714,6 +725,8 @@ def cmd_chat(args) -> None:
714
725
  agent.mcp.close()
715
726
  if agent.sandbox:
716
727
  agent.sandbox.stop()
728
+ if worktree is not None:
729
+ console.print(f"[dim]{escape(worktree.finish())}[/]")
717
730
 
718
731
 
719
732
  def build_parser() -> argparse.ArgumentParser:
@@ -736,6 +749,14 @@ def build_parser() -> argparse.ArgumentParser:
736
749
  metavar="SESSION",
737
750
  help="resume a saved session: pick from a list, or give its number, name or id",
738
751
  )
752
+ parser.add_argument(
753
+ "-w",
754
+ "--worktree",
755
+ nargs="?",
756
+ const="",
757
+ metavar="NAME",
758
+ help="work in a git worktree of its own, on branch NAME (new, or continue one); removed if nothing changed",
759
+ )
739
760
  parser.add_argument("--plan", action="store_true", help="start in plan mode: agree on a plan before any change")
740
761
  parser.add_argument("--auto-edit", action="store_true", help="apply file edits without asking")
741
762
  parser.add_argument("--yolo", action="store_true", help="never ask for permission (edits and commands)")