lcode-cli 0.33.0__tar.gz → 0.34.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.
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/CHANGELOG.md +35 -1
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/PKG-INFO +11 -10
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/README.md +10 -9
- lcode_cli-0.34.0/docs/assets/extra.css +60 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/index.md +3 -2
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/quickstart.md +1 -1
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/usage.md +38 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/mkdocs.yml +2 -2
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/pyproject.toml +3 -0
- lcode_cli-0.34.0/scripts/make_logos.py +62 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/scripts/social-preview.html +7 -19
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/__init__.py +1 -1
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/agent.py +32 -5
- lcode_cli-0.34.0/src/lcode/screenshots.py +1086 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/tools.py +112 -1
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_agent.py +19 -0
- lcode_cli-0.34.0/tests/test_screenshots.py +349 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_vision.py +2 -2
- lcode_cli-0.33.0/docs/assets/extra.css +0 -29
- lcode_cli-0.33.0/docs/assets/logo.svg +0 -15
- lcode_cli-0.33.0/docs/assets/social-preview.png +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.editorconfig +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/CODEOWNERS +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/ISSUE_TEMPLATE/model_request.yml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/dependabot.yml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/workflows/ci.yml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/workflows/docs.yml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.github/workflows/release.yml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.gitignore +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/.pre-commit-config.yaml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/AGENTS.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/CODE_OF_CONDUCT.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/CONTRIBUTING.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/LICENSE +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/SECURITY.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/action.yml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/agents.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/assets/demo.svg +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/automation.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/bench.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/changelog.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/commands.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/configuration.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/contributing.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/editors.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/git.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/hooks.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/how-it-works.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/installation.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/lsp.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/mcp.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/memory.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/models.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/sandbox.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/search.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/servers.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/docs/troubleshooting.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/examples/README.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/examples/api/fix_tests.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/examples/commands/review.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/examples/skills/commit-message/SKILL.md +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/examples/skills/commit-message/scripts/staged.sh +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/install.sh +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/overrides/main.html +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/scripts/record_demo.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/__main__.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/acp.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/action.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/api.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/backends.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/bench.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/bench_backend.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/bench_runtime.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/catalog.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/checkpoints.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/checks.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/cli.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/clipboard.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/codesearch.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/config.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/context.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/extensions.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/frontmatter.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/gitflow.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/hardware.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/hooks.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/jobs.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/limits.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/lsp.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/matching.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/__init__.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/auth.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/catalog.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/catalog.toml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/client.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/commands.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/config.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/http.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/manager.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/protocol.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/server.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/mcp/stdio.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/memory.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/models.toml +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/notify.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/ollama.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/permissions.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/planning.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/render.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/repeats.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/repl.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/repomap.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/residency.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/review.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/sandbox.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/secretscan.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/servers/__init__.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/servers/encord.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/servers/valohai.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/servers/xai.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/sessions.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/steer.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/subagents.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/update.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/vision.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/src/lcode/web.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/conftest.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/fake_lsp_server.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/fake_mcp_server.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_acp.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_action.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_api.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_backends.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_bench.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_catalog.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_checkpoints.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_checks.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_cli.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_clipboard.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_codesearch.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_config.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_context.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_context_picker.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_extensions.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_gitflow.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_hooks.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_jobs.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_lsp.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_matching.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_mcp.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_memory.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_permissions.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_plan_mode.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_repeats.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_repomap.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_residency.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_review.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_robustness.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_sandbox.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_secretscan.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_servers.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_sessions.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_steer.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_subagents.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_tools.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_update.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_web.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/tests/test_xai.py +0 -0
- {lcode_cli-0.33.0 → lcode_cli-0.34.0}/uv.lock +0 -0
|
@@ -6,6 +6,38 @@ All notable changes to lcode are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.34.0] - 2026-10-14
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Screenshots without a screen: a `screenshot` tool runs a desktop program or opens a web page the
|
|
14
|
+
way you would see it, saves the shot in `.lcode/screenshots/`, and returns what it shows with the
|
|
15
|
+
sizes behind it. For a Python Qt program, that's each window against the screen, the size its
|
|
16
|
+
layout needs, and the widgets that stick out or overlap. For a web page or a local server
|
|
17
|
+
(headless Chrome), it's the page's size, what scrolls sideways, and the console errors and
|
|
18
|
+
failed requests. Other desktop programs run on a virtual display (Xvfb). See
|
|
19
|
+
[Screenshots](https://nasser1941.github.io/lcode/usage/#screenshots).
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- In a project with a virtual environment (`.venv`, `venv` or `env`), the model is told to run its
|
|
24
|
+
Python (`.venv/bin/python`) rather than plain `python`, which lacks the project's packages. Found
|
|
25
|
+
when the model checked a PySide6 app with the system Python, failed, and stopped checking.
|
|
26
|
+
|
|
27
|
+
## [0.33.1] - 2026-10-14
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- A new logo, on GitHub, PyPI and the docs site (header, favicon, home page and link previews),
|
|
32
|
+
with a light version for dark backgrounds. `scripts/make_logos.py` makes every size from the
|
|
33
|
+
original.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- The README's images and links work on PyPI: the logo, the demo and the links to the license
|
|
38
|
+
and contributing guide were relative, so PyPI showed them broken.
|
|
39
|
+
- The source package is half the size (0.6 MB): it no longer carries the docs' images.
|
|
40
|
+
|
|
9
41
|
## [0.33.0] - 2026-10-14
|
|
10
42
|
|
|
11
43
|
### Added
|
|
@@ -708,7 +740,9 @@ First public release.
|
|
|
708
740
|
- `AGENTS.md` project instructions and `/init` to generate them.
|
|
709
741
|
- One-line installer for Linux and macOS.
|
|
710
742
|
|
|
711
|
-
[Unreleased]: https://github.com/nasser1941/lcode/compare/v0.
|
|
743
|
+
[Unreleased]: https://github.com/nasser1941/lcode/compare/v0.34.0...HEAD
|
|
744
|
+
[0.34.0]: https://github.com/nasser1941/lcode/compare/v0.33.1...v0.34.0
|
|
745
|
+
[0.33.1]: https://github.com/nasser1941/lcode/compare/v0.33.0...v0.33.1
|
|
712
746
|
[0.33.0]: https://github.com/nasser1941/lcode/compare/v0.32.0...v0.33.0
|
|
713
747
|
[0.32.0]: https://github.com/nasser1941/lcode/compare/v0.31.0...v0.32.0
|
|
714
748
|
[0.31.0]: https://github.com/nasser1941/lcode/compare/v0.30.0...v0.31.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: lcode-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.34.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/
|
|
@@ -35,11 +35,12 @@ Requires-Dist: encord>=0.1.200; extra == 'encord'
|
|
|
35
35
|
Description-Content-Type: text/markdown
|
|
36
36
|
|
|
37
37
|
<p align="center">
|
|
38
|
-
<
|
|
38
|
+
<picture>
|
|
39
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nasser1941/lcode/main/docs/assets/logo-dark.png">
|
|
40
|
+
<img src="https://raw.githubusercontent.com/nasser1941/lcode/main/docs/assets/logo.png" width="360" alt="lcode">
|
|
41
|
+
</picture>
|
|
39
42
|
</p>
|
|
40
43
|
|
|
41
|
-
<h1 align="center">lcode</h1>
|
|
42
|
-
|
|
43
44
|
<p align="center">
|
|
44
45
|
<b>A coding agent that runs entirely on your own machine.</b><br>
|
|
45
46
|
Open-weight models · up to 256K tokens of context · your NVIDIA GPU or Apple Silicon Mac · your code stays local
|
|
@@ -49,7 +50,7 @@ Description-Content-Type: text/markdown
|
|
|
49
50
|
<a href="https://github.com/nasser1941/lcode/actions/workflows/ci.yml"><img src="https://github.com/nasser1941/lcode/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
50
51
|
<a href="https://nasser1941.github.io/lcode/"><img src="https://github.com/nasser1941/lcode/actions/workflows/docs.yml/badge.svg" alt="Docs"></a>
|
|
51
52
|
<a href="https://pypi.org/project/lcode-cli/"><img src="https://img.shields.io/pypi/v/lcode-cli.svg" alt="PyPI"></a>
|
|
52
|
-
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
|
|
53
|
+
<a href="https://github.com/nasser1941/lcode/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
|
|
53
54
|
<img src="https://img.shields.io/badge/python-3.10%2B-blue.svg" alt="Python 3.10+">
|
|
54
55
|
<img src="https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20(Apple%20Silicon)-lightgrey.svg" alt="Linux and macOS">
|
|
55
56
|
</p>
|
|
@@ -58,11 +59,11 @@ Description-Content-Type: text/markdown
|
|
|
58
59
|
<a href="https://nasser1941.github.io/lcode/"><b>Documentation</b></a> ·
|
|
59
60
|
<a href="https://nasser1941.github.io/lcode/installation/">Install</a> ·
|
|
60
61
|
<a href="https://nasser1941.github.io/lcode/models/">Models</a> ·
|
|
61
|
-
<a href="CONTRIBUTING.md">Contributing</a>
|
|
62
|
+
<a href="https://github.com/nasser1941/lcode/blob/main/CONTRIBUTING.md">Contributing</a>
|
|
62
63
|
</p>
|
|
63
64
|
|
|
64
65
|
<p align="center">
|
|
65
|
-
<img src="docs/assets/demo.svg" alt="lcode finding and fixing a bug, then running the tests" width="820">
|
|
66
|
+
<img src="https://raw.githubusercontent.com/nasser1941/lcode/main/docs/assets/demo.svg" alt="lcode finding and fixing a bug, then running the tests" width="820">
|
|
66
67
|
</p>
|
|
67
68
|
|
|
68
69
|
Point lcode at a repository and talk to it in your terminal. It explores the code, answers
|
|
@@ -222,8 +223,8 @@ See the pinned [Roadmap issue](https://github.com/nasser1941/lcode/issues/10). N
|
|
|
222
223
|
## Contributing
|
|
223
224
|
|
|
224
225
|
Contributions are welcome: bug reports, model test results, docs and code. See
|
|
225
|
-
[CONTRIBUTING.md](CONTRIBUTING.md). Please follow the [code of conduct](CODE_OF_CONDUCT.md), and
|
|
226
|
-
report security issues privately as described in [SECURITY.md](SECURITY.md).
|
|
226
|
+
[CONTRIBUTING.md](https://github.com/nasser1941/lcode/blob/main/CONTRIBUTING.md). Please follow the [code of conduct](https://github.com/nasser1941/lcode/blob/main/CODE_OF_CONDUCT.md), and
|
|
227
|
+
report security issues privately as described in [SECURITY.md](https://github.com/nasser1941/lcode/blob/main/SECURITY.md).
|
|
227
228
|
|
|
228
229
|
## Acknowledgements
|
|
229
230
|
|
|
@@ -234,4 +235,4 @@ the open-weight models from Qwen, Poolside, NVIDIA and OpenAI,
|
|
|
234
235
|
|
|
235
236
|
## License
|
|
236
237
|
|
|
237
|
-
[MIT](LICENSE) © 2026 Naser Derakhshan
|
|
238
|
+
[MIT](https://github.com/nasser1941/lcode/blob/main/LICENSE) © 2026 Naser Derakhshan
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nasser1941/lcode/main/docs/assets/logo-dark.png">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/nasser1941/lcode/main/docs/assets/logo.png" width="360" alt="lcode">
|
|
5
|
+
</picture>
|
|
3
6
|
</p>
|
|
4
7
|
|
|
5
|
-
<h1 align="center">lcode</h1>
|
|
6
|
-
|
|
7
8
|
<p align="center">
|
|
8
9
|
<b>A coding agent that runs entirely on your own machine.</b><br>
|
|
9
10
|
Open-weight models · up to 256K tokens of context · your NVIDIA GPU or Apple Silicon Mac · your code stays local
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
<a href="https://github.com/nasser1941/lcode/actions/workflows/ci.yml"><img src="https://github.com/nasser1941/lcode/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
14
15
|
<a href="https://nasser1941.github.io/lcode/"><img src="https://github.com/nasser1941/lcode/actions/workflows/docs.yml/badge.svg" alt="Docs"></a>
|
|
15
16
|
<a href="https://pypi.org/project/lcode-cli/"><img src="https://img.shields.io/pypi/v/lcode-cli.svg" alt="PyPI"></a>
|
|
16
|
-
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
|
|
17
|
+
<a href="https://github.com/nasser1941/lcode/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
|
|
17
18
|
<img src="https://img.shields.io/badge/python-3.10%2B-blue.svg" alt="Python 3.10+">
|
|
18
19
|
<img src="https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20(Apple%20Silicon)-lightgrey.svg" alt="Linux and macOS">
|
|
19
20
|
</p>
|
|
@@ -22,11 +23,11 @@
|
|
|
22
23
|
<a href="https://nasser1941.github.io/lcode/"><b>Documentation</b></a> ·
|
|
23
24
|
<a href="https://nasser1941.github.io/lcode/installation/">Install</a> ·
|
|
24
25
|
<a href="https://nasser1941.github.io/lcode/models/">Models</a> ·
|
|
25
|
-
<a href="CONTRIBUTING.md">Contributing</a>
|
|
26
|
+
<a href="https://github.com/nasser1941/lcode/blob/main/CONTRIBUTING.md">Contributing</a>
|
|
26
27
|
</p>
|
|
27
28
|
|
|
28
29
|
<p align="center">
|
|
29
|
-
<img src="docs/assets/demo.svg" alt="lcode finding and fixing a bug, then running the tests" width="820">
|
|
30
|
+
<img src="https://raw.githubusercontent.com/nasser1941/lcode/main/docs/assets/demo.svg" alt="lcode finding and fixing a bug, then running the tests" width="820">
|
|
30
31
|
</p>
|
|
31
32
|
|
|
32
33
|
Point lcode at a repository and talk to it in your terminal. It explores the code, answers
|
|
@@ -186,8 +187,8 @@ See the pinned [Roadmap issue](https://github.com/nasser1941/lcode/issues/10). N
|
|
|
186
187
|
## Contributing
|
|
187
188
|
|
|
188
189
|
Contributions are welcome: bug reports, model test results, docs and code. See
|
|
189
|
-
[CONTRIBUTING.md](CONTRIBUTING.md). Please follow the [code of conduct](CODE_OF_CONDUCT.md), and
|
|
190
|
-
report security issues privately as described in [SECURITY.md](SECURITY.md).
|
|
190
|
+
[CONTRIBUTING.md](https://github.com/nasser1941/lcode/blob/main/CONTRIBUTING.md). Please follow the [code of conduct](https://github.com/nasser1941/lcode/blob/main/CODE_OF_CONDUCT.md), and
|
|
191
|
+
report security issues privately as described in [SECURITY.md](https://github.com/nasser1941/lcode/blob/main/SECURITY.md).
|
|
191
192
|
|
|
192
193
|
## Acknowledgements
|
|
193
194
|
|
|
@@ -198,4 +199,4 @@ the open-weight models from Qwen, Poolside, NVIDIA and OpenAI,
|
|
|
198
199
|
|
|
199
200
|
## License
|
|
200
201
|
|
|
201
|
-
[MIT](LICENSE) © 2026 Naser Derakhshan
|
|
202
|
+
[MIT](https://github.com/nasser1941/lcode/blob/main/LICENSE) © 2026 Naser Derakhshan
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
.hero {
|
|
2
|
+
text-align: center;
|
|
3
|
+
padding: 1.5rem 0 0.5rem;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.hero h1 {
|
|
7
|
+
font-size: 3rem;
|
|
8
|
+
font-weight: 800;
|
|
9
|
+
margin: 0.5rem 0 0.25rem;
|
|
10
|
+
letter-spacing: -0.02em;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.hero-logo {
|
|
14
|
+
width: 360px;
|
|
15
|
+
max-width: 80%;
|
|
16
|
+
height: auto;
|
|
17
|
+
margin: 0.5rem 0 0.75rem;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.hero p {
|
|
21
|
+
font-size: 1.1rem;
|
|
22
|
+
max-width: 44rem;
|
|
23
|
+
margin: 0.5rem auto 1.25rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.demo {
|
|
27
|
+
display: block;
|
|
28
|
+
margin: 1.5rem auto;
|
|
29
|
+
border-radius: 10px;
|
|
30
|
+
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* In the page for screen readers and search, but the logo shows the name. */
|
|
34
|
+
.sr-only {
|
|
35
|
+
position: absolute;
|
|
36
|
+
width: 1px;
|
|
37
|
+
height: 1px;
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
clip: rect(0, 0, 0, 0);
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* The buttons in the logo's colours. */
|
|
44
|
+
.hero .md-button {
|
|
45
|
+
border-color: #00b8cc;
|
|
46
|
+
color: inherit;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.hero .md-button--primary {
|
|
50
|
+
background-color: #00e3fc;
|
|
51
|
+
border-color: #00e3fc;
|
|
52
|
+
color: #0a0e10;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.hero .md-button:hover,
|
|
56
|
+
.hero .md-button:focus {
|
|
57
|
+
background-color: #00b8cc;
|
|
58
|
+
border-color: #00b8cc;
|
|
59
|
+
color: #0a0e10;
|
|
60
|
+
}
|
|
@@ -7,9 +7,10 @@ hide:
|
|
|
7
7
|
|
|
8
8
|
<div class="hero" markdown>
|
|
9
9
|
|
|
10
|
-
{ .hero-logo }
|
|
11
|
+
{ .hero-logo }
|
|
11
12
|
|
|
12
|
-
# lcode
|
|
13
|
+
# lcode { .sr-only }
|
|
13
14
|
|
|
14
15
|
**A coding agent that runs entirely on your own machine.**
|
|
15
16
|
Open-weight models · up to 256K tokens of context · your NVIDIA GPU or Apple Silicon Mac · your code stays local.
|
|
@@ -106,6 +106,7 @@ reasoning is on.
|
|
|
106
106
|
| `web_search` | Search the web for current information (needs a [search provider](#web-search)) |
|
|
107
107
|
| `web_fetch` | Read a web page or text file by URL as clean text |
|
|
108
108
|
| `view_image` | Look at an image: a model that can see describes it ([Images](#images)) |
|
|
109
|
+
| `screenshot` | Run a desktop program or open a web page without a screen, and see it with its sizes ([Screenshots](#screenshots)) |
|
|
109
110
|
| `agent` | Hand a task to a [subagent](agents.md) with its own context; only its report comes back |
|
|
110
111
|
| `memory` | Save, update or delete [notes](memory.md) that later sessions load |
|
|
111
112
|
| `repo_map` | The [repository map](search.md): important files, classes and functions, ranked (larger repositories; small ones get it in the instructions) |
|
|
@@ -342,6 +343,43 @@ Loading a second model takes a moment: on a 12 GB GPU, describing an image with
|
|
|
342
343
|
`qwen3.6:35b-a3b-coding` takes about a minute, and the next request reloads the main model. Turn
|
|
343
344
|
image support off with `lcode config set vision_model off`.
|
|
344
345
|
|
|
346
|
+
## Screenshots
|
|
347
|
+
|
|
348
|
+
Layout bugs are invisible in the code: a window bigger than the screen, panels cut off, a page that
|
|
349
|
+
scrolls sideways. With the `screenshot` tool the model runs the program, or opens the page, without
|
|
350
|
+
a screen and sees what you would, measured:
|
|
351
|
+
|
|
352
|
+
```text
|
|
353
|
+
● screenshot(python camera_wall.py)
|
|
354
|
+
⎿ .lcode/screenshots/20261014-120211-camera-wall.png (Qt offscreen (PyQt6), 1366x768 screen)
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
```text
|
|
358
|
+
- Window "Camera Wall" (CameraWall): 1362x764 at (0, 0)
|
|
359
|
+
Its layout needs at least 1950x984, more than the screen has
|
|
360
|
+
Sticks out of the window: Panel #panel-4: 640x480 at (9, 385)
|
|
361
|
+
Overlap (190x480): Panel #panel-1: 640x480 at (9, 9) and Panel #panel-2: 640x480 at (459, 9)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
| What | How | Besides the picture |
|
|
365
|
+
|---|---|---|
|
|
366
|
+
| A Python Qt program (PyQt5/6, PySide2/6) | Qt's offscreen platform, on a screen of the size asked for (Qt 6) | Each window's size and position, the size its layout needs, widgets that stick out or overlap |
|
|
367
|
+
| Any other desktop program (Linux) | A virtual display, Xvfb | The size and position of each window |
|
|
368
|
+
| A web page, an `.html` file or a local server | Headless Chrome, Chromium or Edge (Firefox takes the picture only) | The page's size against the window and what sticks out sideways, console errors, failed requests |
|
|
369
|
+
|
|
370
|
+
- For a web app, the model gives the command that starts the server and the page's URL: lcode
|
|
371
|
+
starts the server, waits for the page to answer, takes the shot and stops the server.
|
|
372
|
+
- A model that can see describes the picture with the model's question in mind (see
|
|
373
|
+
[Which model looks](#images)). Without one, the measurements still come back.
|
|
374
|
+
- Shots are saved in `.lcode/screenshots/` in the project, which keeps itself out of git, so you
|
|
375
|
+
can look too.
|
|
376
|
+
- Running a program asks for permission like any command. A web page that isn't local follows the
|
|
377
|
+
`web` setting. With the [sandbox](sandbox.md) on, programs can't be shown, since they don't run on
|
|
378
|
+
your machine.
|
|
379
|
+
- Needs: Xvfb for other desktop programs (`sudo apt install xvfb x11-apps`), and Chrome or
|
|
380
|
+
Chromium for web pages. On macOS only Qt programs and web pages work, since there's no virtual
|
|
381
|
+
display.
|
|
382
|
+
|
|
345
383
|
## Permissions
|
|
346
384
|
|
|
347
385
|
| Mode | File edits | Shell commands |
|
|
@@ -9,8 +9,8 @@ copyright: Copyright © 2026 Naser Derakhshan · <a href="https://github.com
|
|
|
9
9
|
theme:
|
|
10
10
|
name: material
|
|
11
11
|
custom_dir: overrides
|
|
12
|
-
logo: assets/
|
|
13
|
-
favicon: assets/
|
|
12
|
+
logo: assets/icon.png
|
|
13
|
+
favicon: assets/favicon.png
|
|
14
14
|
icon:
|
|
15
15
|
repo: fontawesome/brands/github
|
|
16
16
|
font:
|
|
@@ -61,6 +61,9 @@ path = "src/lcode/__init__.py"
|
|
|
61
61
|
[tool.hatch.build.targets.wheel]
|
|
62
62
|
packages = ["src/lcode"]
|
|
63
63
|
|
|
64
|
+
[tool.hatch.build.targets.sdist]
|
|
65
|
+
exclude = ["docs/assets/*.png"] # images for the README and the docs site: not needed to build or install
|
|
66
|
+
|
|
64
67
|
[tool.ruff]
|
|
65
68
|
line-length = 120
|
|
66
69
|
target-version = "py310"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Make the logo files the README, the docs and PyPI use, from docs/assets/logo-original.png.
|
|
2
|
+
|
|
3
|
+
uv run --with pillow python scripts/make_logos.py
|
|
4
|
+
|
|
5
|
+
- logo.png: the mark and the name, for light backgrounds
|
|
6
|
+
- logo-dark.png: the same with a light name, for dark backgrounds (GitHub's dark mode, the docs' dark scheme)
|
|
7
|
+
- icon.png: the mark alone, square (the docs' header)
|
|
8
|
+
- favicon.png: the mark, small (browser tabs)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from PIL import Image
|
|
14
|
+
|
|
15
|
+
ASSETS = Path(__file__).resolve().parent.parent / "docs" / "assets"
|
|
16
|
+
WIDTH = 1200 # sharp at the README's 360 pixels on a 3x screen
|
|
17
|
+
LIGHT_TEXT = (230, 237, 243) # GitHub's dark-mode text colour
|
|
18
|
+
PAD = 0.03 # around the logo, as a share of its width
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_mark(r: int, g: int, b: int) -> bool:
|
|
22
|
+
return b > 120 and g > 100 and r < 120 # the cyan of the mark (anti-aliased edges included)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main() -> None:
|
|
26
|
+
original = Image.open(ASSETS / "logo-original.png").convert("RGBA")
|
|
27
|
+
box = original.getchannel("A").point(lambda a: 255 if a > 8 else 0).getbbox()
|
|
28
|
+
logo = original.crop(box)
|
|
29
|
+
pad = int(logo.width * PAD)
|
|
30
|
+
framed = Image.new("RGBA", (logo.width + 2 * pad, logo.height + 2 * pad))
|
|
31
|
+
framed.paste(logo, (pad, pad))
|
|
32
|
+
height = round(framed.height * WIDTH / framed.width)
|
|
33
|
+
light = framed.resize((WIDTH, height), Image.LANCZOS)
|
|
34
|
+
light.save(ASSETS / "logo.png", optimize=True)
|
|
35
|
+
|
|
36
|
+
dark = light.copy()
|
|
37
|
+
pixels = dark.load()
|
|
38
|
+
for y in range(dark.height):
|
|
39
|
+
for x in range(dark.width):
|
|
40
|
+
r, g, b, a = pixels[x, y]
|
|
41
|
+
if a and not is_mark(r, g, b):
|
|
42
|
+
pixels[x, y] = (*LIGHT_TEXT, a)
|
|
43
|
+
dark.save(ASSETS / "logo-dark.png", optimize=True)
|
|
44
|
+
|
|
45
|
+
# The mark: the cyan part on the left.
|
|
46
|
+
cyan = Image.new("L", logo.size)
|
|
47
|
+
lp, cp = logo.load(), cyan.load()
|
|
48
|
+
for y in range(logo.height):
|
|
49
|
+
for x in range(logo.width):
|
|
50
|
+
r, g, b, a = lp[x, y]
|
|
51
|
+
if a > 8 and is_mark(r, g, b):
|
|
52
|
+
cp[x, y] = 255
|
|
53
|
+
mark = logo.crop(cyan.getbbox())
|
|
54
|
+
side = round(max(mark.size) * 1.12)
|
|
55
|
+
square = Image.new("RGBA", (side, side))
|
|
56
|
+
square.paste(mark, ((side - mark.width) // 2, (side - mark.height) // 2))
|
|
57
|
+
square.resize((512, 512), Image.LANCZOS).save(ASSETS / "icon.png", optimize=True)
|
|
58
|
+
square.resize((96, 96), Image.LANCZOS).save(ASSETS / "favicon.png", optimize=True)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if __name__ == "__main__":
|
|
62
|
+
main()
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&family=JetBrains+Mono:wght@400;700&display=block" rel="stylesheet">
|
|
10
10
|
<style>
|
|
11
|
-
:root { --cyan: #
|
|
11
|
+
:root { --cyan: #00e3fc; --cyan-light: #8ef4ff; --text: #e6edf3; --muted: #94a3b8; }
|
|
12
12
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
13
13
|
html, body { width: 1280px; height: 640px; overflow: hidden; }
|
|
14
14
|
body {
|
|
15
15
|
font-family: Inter, system-ui, sans-serif; color: var(--text);
|
|
16
16
|
background:
|
|
17
|
-
radial-gradient(900px 500px at 85% 20%, rgba(
|
|
18
|
-
radial-gradient(700px 500px at 10% 90%, rgba(
|
|
17
|
+
radial-gradient(900px 500px at 85% 20%, rgba(0, 227, 252, 0.14), transparent 60%),
|
|
18
|
+
radial-gradient(700px 500px at 10% 90%, rgba(0, 227, 252, 0.16), transparent 60%),
|
|
19
19
|
linear-gradient(135deg, #0b1120 0%, #0f172a 55%, #111827 100%);
|
|
20
20
|
display: flex; align-items: center; padding: 64px 72px; gap: 56px;
|
|
21
21
|
}
|
|
@@ -25,12 +25,11 @@
|
|
|
25
25
|
background-size: 40px 40px;
|
|
26
26
|
}
|
|
27
27
|
.left { flex: 1 1 0; position: relative; }
|
|
28
|
-
.brand {
|
|
29
|
-
.brand
|
|
30
|
-
h1 { font-size: 104px; font-weight: 800; letter-spacing: -0.04em; line-height: 1; }
|
|
28
|
+
.brand { margin: 0 0 30px -10px; }
|
|
29
|
+
.brand img { height: 118px; display: block; filter: drop-shadow(0 10px 30px rgba(0, 227, 252, 0.22)); }
|
|
31
30
|
.tagline { font-size: 34px; font-weight: 600; line-height: 1.25; margin-bottom: 30px; max-width: 560px; }
|
|
32
31
|
.tagline span {
|
|
33
|
-
background: linear-gradient(90deg, var(--cyan), var(--
|
|
32
|
+
background: linear-gradient(90deg, var(--cyan), var(--cyan-light)); -webkit-background-clip: text; color: transparent;
|
|
34
33
|
}
|
|
35
34
|
.chips { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 34px; max-width: 580px; }
|
|
36
35
|
.chip {
|
|
@@ -56,18 +55,7 @@
|
|
|
56
55
|
</head>
|
|
57
56
|
<body>
|
|
58
57
|
<div class="left">
|
|
59
|
-
<div class="brand">
|
|
60
|
-
<svg viewBox="0 0 128 128" aria-hidden="true">
|
|
61
|
-
<defs>
|
|
62
|
-
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#1e293b"/><stop offset="1" stop-color="#0f172a"/></linearGradient>
|
|
63
|
-
<linearGradient id="fg" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#22d3ee"/><stop offset="1" stop-color="#a78bfa"/></linearGradient>
|
|
64
|
-
</defs>
|
|
65
|
-
<rect width="128" height="128" rx="28" fill="url(#bg)" stroke="rgba(148,163,184,.35)" stroke-width="2"/>
|
|
66
|
-
<path d="M34 40 L62 64 L34 88" fill="none" stroke="url(#fg)" stroke-width="12" stroke-linecap="round" stroke-linejoin="round"/>
|
|
67
|
-
<rect x="70" y="80" width="30" height="10" rx="5" fill="url(#fg)"/>
|
|
68
|
-
</svg>
|
|
69
|
-
<h1>lcode</h1>
|
|
70
|
-
</div>
|
|
58
|
+
<div class="brand"><img src="../docs/assets/logo-dark.png" alt="lcode"></div>
|
|
71
59
|
<p class="tagline">A coding agent that runs <span>entirely on your own machine.</span></p>
|
|
72
60
|
<div class="chips">
|
|
73
61
|
<div class="chip">Open-weight models</div>
|
|
@@ -48,7 +48,7 @@ from lcode.config import format_tokens
|
|
|
48
48
|
from lcode.jobs import Jobs
|
|
49
49
|
from lcode.mcp import McpManager
|
|
50
50
|
from lcode.ollama import Ollama, OllamaError
|
|
51
|
-
from lcode.permissions import Permissions
|
|
51
|
+
from lcode.permissions import LEADING_CD, Permissions
|
|
52
52
|
from lcode.render import MarkdownStreamer
|
|
53
53
|
from lcode.repeats import Repeats
|
|
54
54
|
from lcode.sandbox import Sandbox, SandboxError, project_root
|
|
@@ -122,7 +122,7 @@ SYSTEM_PROMPT = """You are lcode, an autonomous software-engineering agent runni
|
|
|
122
122
|
# Verifying your work
|
|
123
123
|
- A syntax check or an import only shows that code loads. Run what you changed the way it will be used (the script, the tests, the app) and fix what fails.
|
|
124
124
|
- To fix a bug, first reproduce each problem the user reports with a test, a command or a short script, then run the same checks to show they're gone.
|
|
125
|
-
- For what you can't see, like a GUI, a web page or a layout,
|
|
125
|
+
- For what you can't see, like a GUI, a web page or a layout, use the screenshot tool: it runs the program (or opens the page) without a screen and returns what it shows, with the sizes of windows, widgets or the page measured{look}. Measure instead of assuming.
|
|
126
126
|
- Never claim something works, mark a todo done, or call it tested unless you ran it. If you couldn't check something, say so and tell the user exactly what to look for. If something fails, say so and show the relevant error.{checks}
|
|
127
127
|
|
|
128
128
|
# Communication
|
|
@@ -131,7 +131,7 @@ SYSTEM_PROMPT = """You are lcode, an autonomous software-engineering agent runni
|
|
|
131
131
|
|
|
132
132
|
# Environment
|
|
133
133
|
- Working directory: {cwd}
|
|
134
|
-
- OS: {os}; shell: bash; Python command:
|
|
134
|
+
- OS: {os}; shell: bash; Python command: {python}
|
|
135
135
|
- Date: {date}
|
|
136
136
|
- Git: {git}
|
|
137
137
|
|
|
@@ -218,6 +218,30 @@ def call_arguments(call: dict) -> dict:
|
|
|
218
218
|
return args if isinstance(args, dict) else {}
|
|
219
219
|
|
|
220
220
|
|
|
221
|
+
VENV_DIRS = (".venv", "venv", "env")
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def project_python(cwd: Path) -> Path | None:
|
|
225
|
+
"""The project's virtual environment's Python (.venv, venv or env, here or up to the repository's root)."""
|
|
226
|
+
for folder in [cwd, *cwd.parents][:4]:
|
|
227
|
+
for name in VENV_DIRS:
|
|
228
|
+
path = folder / name / "bin" / "python"
|
|
229
|
+
if path.exists() and (folder / name / "pyvenv.cfg").exists():
|
|
230
|
+
return path
|
|
231
|
+
if (folder / ".git").exists():
|
|
232
|
+
break # not beyond the repository
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def python_line(cwd: Path) -> str:
|
|
237
|
+
"""How the system prompt names the Python command."""
|
|
238
|
+
venv = project_python(cwd)
|
|
239
|
+
if venv is None:
|
|
240
|
+
return f"`{'python' if shutil.which('python') else 'python3'}`"
|
|
241
|
+
shown = venv.relative_to(cwd) if cwd in venv.parents else venv
|
|
242
|
+
return f"`{shown}` (the project's virtual environment: plain python lacks its packages)"
|
|
243
|
+
|
|
244
|
+
|
|
221
245
|
class Progress:
|
|
222
246
|
"""The status line under a running request.
|
|
223
247
|
|
|
@@ -372,7 +396,7 @@ class Agent:
|
|
|
372
396
|
model=self.settings.model,
|
|
373
397
|
cwd=self.cwd,
|
|
374
398
|
os=f"{platform.system()} {platform.release()} ({platform.machine()})",
|
|
375
|
-
python=
|
|
399
|
+
python=python_line(self.cwd),
|
|
376
400
|
date=dt.date.today().isoformat(),
|
|
377
401
|
git=git_info(self.cwd),
|
|
378
402
|
tree=tree(self.cwd, depth=1, limit=120),
|
|
@@ -383,7 +407,7 @@ class Agent:
|
|
|
383
407
|
skills=extensions.skills_prompt(self.extensions().skills, self.settings.context),
|
|
384
408
|
code=self.code_prompt(),
|
|
385
409
|
map=self.map_prompt(),
|
|
386
|
-
look="
|
|
410
|
+
look="; look at other images with view_image" if self.vision_model() else "",
|
|
387
411
|
checks=self.checks_prompt(),
|
|
388
412
|
)
|
|
389
413
|
|
|
@@ -1000,6 +1024,9 @@ class Agent:
|
|
|
1000
1024
|
return f"agent({args.get('type', '')}: {args.get('description') or str(args.get('task', ''))[:50]})"
|
|
1001
1025
|
if name == "bash":
|
|
1002
1026
|
return f"$ {str(args.get('command', ''))[:60]}"
|
|
1027
|
+
if name == "screenshot":
|
|
1028
|
+
what = args.get("url") or LEADING_CD.sub("", str(args.get("command") or ""))
|
|
1029
|
+
return f"screenshot({what[:60]})"
|
|
1003
1030
|
if name in ("web_search", "web_fetch", "view_image"):
|
|
1004
1031
|
return f"{name}({args.get('query') or args.get('url') or args.get('path') or ''})"
|
|
1005
1032
|
if self.mcp and self.mcp.owns(name):
|