dotagents-cli 0.7.6__tar.gz → 0.8.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.
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/CHANGELOG.md +59 -1
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/PKG-INFO +6 -1
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/README.md +5 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/guide/commands.md +23 -3
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/guide/overlays.md +43 -5
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/guide/private-sync.md +12 -1
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/AGENTS.md +96 -20
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/__init__.py +1 -1
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_context.py +16 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_env.py +40 -3
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_overlay/dotagents/templates/AGENTS.md +7 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_overlays.py +10 -4
- dotagents_cli-0.8.0/src/dotagents/_pipwheel.py +319 -0
- dotagents_cli-0.8.0/src/dotagents/_pyvenv.py +329 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_resources.py +16 -3
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/cli/build_pyz.py +16 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/cli/init.py +16 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/cli/overlays.py +135 -24
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/conftest.py +21 -1
- dotagents_cli-0.8.0/tests/test_cloud_setup.py +97 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_fix_skills_adapters.py +16 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_init_base.py +15 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_overlays_cli.py +61 -0
- dotagents_cli-0.8.0/tests/test_pipwheel.py +102 -0
- dotagents_cli-0.8.0/tests/test_pyvenv_core.py +216 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tools/cloud-setup.sh +18 -4
- dotagents_cli-0.7.6/tests/test_cloud_setup.py +0 -55
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/.gitignore +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/LICENSE +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/agents.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/cli.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/commands.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/context.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/env.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/fs.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/hooks.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/merge.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/overlays.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/reference.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/resources.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/scope.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/skills.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/sources.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/api/wrappers.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/changelog.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/guide/authoring.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/guide/install.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/docs/index.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/install.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/mkdocs.yml +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/pyproject.toml +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/__main__.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_agents.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_fs.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_hooks.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_ignore.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_merge.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_overlay/dotagents/cmds/findings.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_overlay/dotagents/cmds/launch.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_overlay/dotagents/hooks/preinvocation_antigravity_context.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_overlay/dotagents/hooks/pretooluse_codex_env.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_overlay/dotagents/hooks/sessionstart_codex_context.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_overlay/dotagents/templates/PROJECT.md +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_scope.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_skills.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_sources.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_wrappers.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/cli/__init__.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/cli/_common.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/cli/about.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/cli/context.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/cli/env.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/cli/path.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/py.typed +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/_helpers.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/_shell.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_about.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_agents.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_api_header.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_audit_leak.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_build_pyz.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_cli_main.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_cmds_discovery.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_context.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_env.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_env_cli_scope.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_env_format.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_env_into.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_env_regressions.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_env_safety.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_findings_cmd.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_fix_adapters.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_fix_cli.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_fix_env.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_fix_hooks.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_fix_init.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_fix_overlays.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_fix_packaging.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_fix_scope_context.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_git_ssl_revoke.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_hooks.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_ignore.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_last_mile.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_launch_cmd.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_local_additions.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_mcp.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_no_internal_labels.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_overlay_libs.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_overlays_command.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_path_timeout_frontmatter.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_powershell_env_hook.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_quoting_injection_safety.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_scope.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_sources.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_sources_uri.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_wire_hooks.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tests/test_wrappers.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tools/audit.py +0 -0
- {dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/tools/pyz_smoke.sh +0 -0
|
@@ -7,6 +7,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-10-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `overlays add` takes globs: `overlays add '*' -g` installs every overlay the repos
|
|
15
|
+
offer, which for a store with a registry (`<store>/dotagents.toml`) is everything
|
|
16
|
+
it names. A glob matching nothing is an error.
|
|
17
|
+
- `tools/cloud-setup.sh` installs every overlay the store's registry names
|
|
18
|
+
(`overlays add '*'`) before falling back to installing `private-sync` alone.
|
|
19
|
+
|
|
20
|
+
- Each store has a Python venv, `<store>/.pyvenv/<X.Y.Z>-<os>-<arch>/`, made from
|
|
21
|
+
the Python that runs dotagents, where skills run. `init` and `overlays add` /
|
|
22
|
+
`sync` / `remove` keep it current: the user venv always has duho, and every
|
|
23
|
+
overlay's `requirements.txt` is installed (in one pip run, only when a file
|
|
24
|
+
changed, before the overlay's `setup.py`). A project gets its own venv when one of
|
|
25
|
+
its overlays ships requirements or a `lib/`. `--no-venv` skips it for a run;
|
|
26
|
+
`AGENTS_NO_PYVENV=1` turns it off. `.pyvenv/` holds the agents' venvs only: a
|
|
27
|
+
venv there that no sync completed is never used, and a project's own code keeps
|
|
28
|
+
its venvs in the project tree.
|
|
29
|
+
- The venvs layer project > user > system through a `.pth` file in each: the store's
|
|
30
|
+
own overlay libs, then each lower store's venv packages and libs, then dotagents
|
|
31
|
+
itself. A project venv imports the project's packages first, then the user's.
|
|
32
|
+
- `env` points `AGENTS_PYTHON` at the active venv and names it in `AGENTS_PYVENV`;
|
|
33
|
+
overlay `setup.py` scripts run under it. `context` prints it ("Python for
|
|
34
|
+
skills"), and its JSON form carries it as `python`. The managed block tells
|
|
35
|
+
agents to run skill scripts with `$AGENTS_PYTHON`.
|
|
36
|
+
- pip without ensurepip: a venv where the interpreter has no ensurepip is created
|
|
37
|
+
without pip, and pip runs from its wheel (25.3, the last for Python 3.9, checked
|
|
38
|
+
against a pinned sha256). The wheel is found in the store's cache, in a `.pyz`
|
|
39
|
+
built with the new `build-pyz --with-pip`, in `AGENTS_PIP_SOURCE` (a directory of
|
|
40
|
+
wheels, or any URI pathapi-uri reads) or pip's `find-links`, or on your index
|
|
41
|
+
(`PIP_INDEX_URL`, or the mirror in `pip.ini` / `pip.conf`). `AGENTS_PIP_SOURCE`
|
|
42
|
+
is also passed to pip as `--find-links` for the requirements.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- `overlays add` no longer stops at the first overlay that fails. Each failure is
|
|
47
|
+
logged, the overlays that require the failed one are skipped, every other overlay
|
|
48
|
+
is installed, and the command exits 1 naming each failure. A failed overlay this
|
|
49
|
+
run was installing for the first time is removed again, as before; the ones that
|
|
50
|
+
installed stay.
|
|
51
|
+
- With a scope venv, `env` no longer puts the overlay libs it layers on
|
|
52
|
+
`PYTHONPATH`: the venv's interpreter imports them, and no other Python in the
|
|
53
|
+
session should. Without a venv, `PYTHONPATH` carries them as before.
|
|
54
|
+
`AGENTS_PYTHONPATH` still lists every lib.
|
|
55
|
+
- The base block's "Startup: annotate that you read `…`" line names a store under
|
|
56
|
+
the home directory from there (`~/.agents/AGENTS.md`), and any other store by its
|
|
57
|
+
absolute path as before. A store kept in git and used on machines whose home
|
|
58
|
+
directories differ no longer shows `AGENTS.md` modified on all but one of them.
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
|
|
62
|
+
- `env --cache` on Windows with Python before 3.13 could miss a cache it had just
|
|
63
|
+
written: `time.time()` there lags the file's own timestamp by up to one clock
|
|
64
|
+
tick, and a cache file dated after "now" was treated as stale. A cache file
|
|
65
|
+
dated up to 2 s in the future now counts as fresh.
|
|
66
|
+
|
|
10
67
|
## [0.7.6] - 2026-10-15
|
|
11
68
|
|
|
12
69
|
### Added
|
|
@@ -1470,7 +1527,8 @@ Patch release: the PATH/POSIX-conversion fix above (the only change since 0.3.0)
|
|
|
1470
1527
|
affected module sources (`dotagents.cli`, `duho.presets`) to extracted temp files
|
|
1471
1528
|
before dispatch; a no-op for a plain install.
|
|
1472
1529
|
|
|
1473
|
-
[Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.
|
|
1530
|
+
[Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.8.0...HEAD
|
|
1531
|
+
[0.8.0]: https://github.com/jose-pr/dotagents/compare/v0.7.6...v0.8.0
|
|
1474
1532
|
[0.7.6]: https://github.com/jose-pr/dotagents/compare/v0.7.5...v0.7.6
|
|
1475
1533
|
[0.7.5]: https://github.com/jose-pr/dotagents/compare/v0.7.4...v0.7.5
|
|
1476
1534
|
[0.7.4]: https://github.com/jose-pr/dotagents/compare/v0.7.3...v0.7.4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: dotagents-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: The dotagents CLI: install and manage a portable ~/.agents config for AI coding agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/jose-pr/dotagents/
|
|
6
6
|
Project-URL: Repository, https://github.com/jose-pr/dotagents
|
|
@@ -215,6 +215,11 @@ store's shared `skills/` so every agent sees the same skills.
|
|
|
215
215
|
`.ignore` at the overlay's root match (setup output, local state) and tool caches are left
|
|
216
216
|
alone; `--prune` clears them too. A fresh `add` whose setup script fails is rolled
|
|
217
217
|
back.
|
|
218
|
+
- Each store has a Python venv, `<store>/.pyvenv/<version>-<os>-<arch>/`, where skills
|
|
219
|
+
run (`$AGENTS_PYTHON`): duho, every overlay's `requirements.txt` and every overlay
|
|
220
|
+
`lib/` import there, layered project > user > system. pip comes from the
|
|
221
|
+
interpreter, else its pinned wheel (cache, `AGENTS_PIP_SOURCE`, your index mirror,
|
|
222
|
+
or a `.pyz` built `--with-pip`).
|
|
218
223
|
- `sync` refreshes each overlay from the repo it was installed from (`--repo` replaces
|
|
219
224
|
that source), installs a `requires` added upstream, and re-merges the managed block.
|
|
220
225
|
- `remove` deletes the overlay's directory, unpublishes only the skills **it**
|
|
@@ -160,6 +160,11 @@ store's shared `skills/` so every agent sees the same skills.
|
|
|
160
160
|
`.ignore` at the overlay's root match (setup output, local state) and tool caches are left
|
|
161
161
|
alone; `--prune` clears them too. A fresh `add` whose setup script fails is rolled
|
|
162
162
|
back.
|
|
163
|
+
- Each store has a Python venv, `<store>/.pyvenv/<version>-<os>-<arch>/`, where skills
|
|
164
|
+
run (`$AGENTS_PYTHON`): duho, every overlay's `requirements.txt` and every overlay
|
|
165
|
+
`lib/` import there, layered project > user > system. pip comes from the
|
|
166
|
+
interpreter, else its pinned wheel (cache, `AGENTS_PIP_SOURCE`, your index mirror,
|
|
167
|
+
or a `.pyz` built `--with-pip`).
|
|
163
168
|
- `sync` refreshes each overlay from the repo it was installed from (`--repo` replaces
|
|
164
169
|
that source), installs a `requires` added upstream, and re-merges the managed block.
|
|
165
170
|
- `remove` deletes the overlay's directory, unpublishes only the skills **it**
|
|
@@ -100,10 +100,15 @@ dotagents init # base config into ./.agents (project sc
|
|
|
100
100
|
dotagents init -g # ...into ~/.agents (user scope)
|
|
101
101
|
dotagents init --bin-dir ~/.local/bin # also write a `dotagents` command on PATH
|
|
102
102
|
dotagents init --no-hooks # skip agent hook wiring + the skills links
|
|
103
|
+
dotagents init --no-venv # skip the store's Python venv (duho for skills)
|
|
103
104
|
dotagents init --agents claude,codex # exactly these agents (default: detected + claude)
|
|
104
105
|
dotagents init --dry-run
|
|
105
106
|
```
|
|
106
107
|
|
|
108
|
+
`init` also creates or updates the store's Python venv, where skills run (see
|
|
109
|
+
[the scope venv](overlays.md#python-dependencies-and-the-scope-venv)). Offline, or
|
|
110
|
+
with no pip to be had, that is a warning; `overlays sync` retries.
|
|
111
|
+
|
|
107
112
|
### Hook wiring
|
|
108
113
|
|
|
109
114
|
For each active agent, `init` adds what that harness needs to load the config, and
|
|
@@ -198,6 +203,7 @@ Manages opt-in overlays **by name**. See [Overlays](overlays.md) for the full mo
|
|
|
198
203
|
|
|
199
204
|
```bash
|
|
200
205
|
dotagents overlays add python engineering # install into the scope, publish skills, merge rules/routing
|
|
206
|
+
dotagents overlays add '*' -g # everything the repos offer (a store registry: all it names)
|
|
201
207
|
dotagents overlays list # installed (discovered) + available from the repos
|
|
202
208
|
dotagents overlays sync 'py*' # refresh installed overlays matching a glob
|
|
203
209
|
dotagents overlays sync --prune # also clear what .gitignore/.ignore protect: exactly upstream
|
|
@@ -205,7 +211,14 @@ dotagents overlays remove python # delete the overlay dir, unpublish i
|
|
|
205
211
|
dotagents overlays show python # describe one: manifest, requires, setup, skills, source (--json)
|
|
206
212
|
```
|
|
207
213
|
|
|
208
|
-
- **`add`**
|
|
214
|
+
- **`add`** takes names or globs: `'*'` is every overlay the repos offer, so with
|
|
215
|
+
a store registry it installs everything the registry names, and `'py*'` the ones
|
|
216
|
+
starting with `py`; a glob that matches nothing is an error. One overlay failing
|
|
217
|
+
(its copy, requirements or setup) does not stop the rest: it is logged, what
|
|
218
|
+
requires it is skipped, everything else installs, and the command exits 1 naming
|
|
219
|
+
each failure. A failed overlay this run was installing for the first time is
|
|
220
|
+
removed again; one that was already installed is left in place, not set up.
|
|
221
|
+
`add` installs what each manifest's `requires` names first, each requirement
|
|
209
222
|
installed and set up before the overlay that needs it (`--no-requires` to skip); a
|
|
210
223
|
requirement the scope already has, in its own store or the user store for a project,
|
|
211
224
|
is satisfied and left alone, while a name you ask for explicitly is always
|
|
@@ -213,8 +226,11 @@ dotagents overlays show python # describe one: manifest, requires, s
|
|
|
213
226
|
before touching anything — the first repo that offers a name wins — records where
|
|
214
227
|
each overlay came from, and publishes skills from the installed copy, never
|
|
215
228
|
replacing a skill already in the shared `skills/` dir (and links them into
|
|
216
|
-
Claude's skills dir when `init` wired Claude for the store).
|
|
217
|
-
|
|
229
|
+
Claude's skills dir when `init` wired Claude for the store). Each overlay's
|
|
230
|
+
`requirements.txt` is installed into the scope venv before its setup script runs
|
|
231
|
+
(`--no-venv` skips it; see
|
|
232
|
+
[the scope venv](overlays.md#python-dependencies-and-the-scope-venv)). A fresh install
|
|
233
|
+
whose requirements or setup script fail is rolled back. A source inside the store's own `overlays/` directory
|
|
218
234
|
is refused (by `sync` too): `remove` would delete the only copy.
|
|
219
235
|
- `add`, `remove` and `show` without an overlay name are usage errors (exit 2), and
|
|
220
236
|
a `--dry-run` says what it would write (`would recompose ...`) instead of reporting
|
|
@@ -590,6 +606,7 @@ is not listed.
|
|
|
590
606
|
```bash
|
|
591
607
|
python -m dotagents build-pyz --out dist/dotagents.pyz
|
|
592
608
|
python -m dotagents build-pyz --extras uri,repo # also vendor what those extras install
|
|
609
|
+
python -m dotagents build-pyz --with-pip # also carry pip, for machines without it
|
|
593
610
|
```
|
|
594
611
|
|
|
595
612
|
Builds a self-contained zipapp from a source checkout, with `duho` and `pathapi`
|
|
@@ -608,6 +625,9 @@ vendored (plus what the dotagents-cli extras named by `--extras` install), so it
|
|
|
608
625
|
vendored as pure-Python wheels resolved for Python 3.9, so the file does not
|
|
609
626
|
depend on the machine that built it; `sftp` needs native modules and fails the
|
|
610
627
|
build with a message saying so. The archive is compressed.
|
|
628
|
+
- `--with-pip` — also vendor the pinned pip wheel (about 1.8 MB), so the `.pyz` can
|
|
629
|
+
set up the scope venv where Python has no ensurepip and no index is reachable
|
|
630
|
+
(see [the scope venv](overlays.md#python-dependencies-and-the-scope-venv)).
|
|
611
631
|
|
|
612
632
|
Each release attaches a built one:
|
|
613
633
|
<https://github.com/jose-pr/dotagents/releases/latest/download/dotagents.pyz>.
|
|
@@ -226,12 +226,49 @@ copies, where symlinks are unavailable) into the scope's shared skills dir, so e
|
|
|
226
226
|
agent that reads that dir picks up the same skills. Removing the overlay unpublishes
|
|
227
227
|
only the skills it published, then sweeps any now-broken symlinks.
|
|
228
228
|
|
|
229
|
+
## Python dependencies and the scope venv
|
|
230
|
+
|
|
231
|
+
Every store has a Python venv, `<store>/.pyvenv/<X.Y.Z>-<os>-<arch>/` (for example
|
|
232
|
+
`~/.agents/.pyvenv/3.14.7-nt-arm64`), made from the Python that runs dotagents.
|
|
233
|
+
A store's `.pyvenv/` holds these **agents' venvs only**: skills, overlay helpers and
|
|
234
|
+
setup scripts run there. A project's own code gets its venvs beside the store, in
|
|
235
|
+
the project root's `.pyvenv/` (`<project>/.pyvenv/<version>-<os>-<arch>/`, which the
|
|
236
|
+
python overlay's `dotagents pyvenv` creates); only a venv dotagents itself synced is
|
|
237
|
+
ever used as an agents' venv. `init` and every
|
|
238
|
+
`overlays add` / `sync` / `remove` keep it current:
|
|
239
|
+
|
|
240
|
+
- The user store's venv always has **duho**, so any skill can build a command line
|
|
241
|
+
on it, plus the packages each overlay installed there lists in a
|
|
242
|
+
**`requirements.txt`** at its root (pip's format). They are installed in one pip
|
|
243
|
+
run, so pip sees every constraint at once, and only when a file changed.
|
|
244
|
+
- A project gets its own venv only when one of its overlays ships a
|
|
245
|
+
`requirements.txt` or a `lib/`; otherwise a project session uses the user venv.
|
|
246
|
+
- The venvs **layer like everything else**. A `.pth` file in each venv lists, highest
|
|
247
|
+
precedence first: the store's own overlay libs, then the user venv's packages and
|
|
248
|
+
libs, then the system store's. dotagents itself comes last. So in a project venv,
|
|
249
|
+
the project's packages and libs win, then the user's, then the system's.
|
|
250
|
+
- `dotagents env` points **`AGENTS_PYTHON`** at the active venv (and names it in
|
|
251
|
+
`AGENTS_PYVENV`). Overlay `setup.py` and `env.py` run under it, and the managed
|
|
252
|
+
block tells agents to run skill scripts with it. Libs the venv layers stay off
|
|
253
|
+
`PYTHONPATH`, so no other Python in the session, such as a project's own venv,
|
|
254
|
+
imports them by accident.
|
|
255
|
+
|
|
256
|
+
**No ensurepip, no network?** pip runs from its wheel, pinned by version (25.3, the
|
|
257
|
+
last for Python 3.9) and hash, found in this order: the store's cache, a copy
|
|
258
|
+
vendored into the `.pyz` (`build-pyz --with-pip`), `AGENTS_PIP_SOURCE` (a directory
|
|
259
|
+
of wheels, or any URI pathapi-uri reads: `file:`, `s3:`, `sftp:`, ...), pip's own
|
|
260
|
+
`find-links`, then your index (`PIP_INDEX_URL` or the mirror in `pip.ini` /
|
|
261
|
+
`pip.conf`). `AGENTS_PIP_SOURCE` is also handed to pip as `--find-links` for the
|
|
262
|
+
requirements themselves.
|
|
263
|
+
|
|
264
|
+
Opt out per run with `--no-venv`, or for good with `AGENTS_NO_PYVENV=1`.
|
|
265
|
+
|
|
229
266
|
## Setup scripts
|
|
230
267
|
|
|
231
268
|
An overlay may ship an **idempotent** `setup.py` at its root — the recommended,
|
|
232
|
-
OS-agnostic form: it runs under the
|
|
233
|
-
|
|
234
|
-
in, dotagents runs the script automatically. Reserve it for real install-time work:
|
|
269
|
+
OS-agnostic form: it runs under `AGENTS_PYTHON` (the scope venv above, with the
|
|
270
|
+
overlay's requirements installed first), so it works on every platform. After
|
|
271
|
+
`add` / `sync` copies the overlay in, dotagents runs the script automatically. Reserve it for real install-time work:
|
|
235
272
|
`PATH`, `PYTHONPATH` and `$<NAME>_OVERLAY_ROOT` are `dotagents env`'s job
|
|
236
273
|
(above), and an overlay's own env vars belong in its `env.py`, not in a script that
|
|
237
274
|
writes one into the store — none of the example overlays ship a setup script any more.
|
|
@@ -242,8 +279,9 @@ Presence of a script is the opt-in; skip it with `--no-setup`. The author contra
|
|
|
242
279
|
- **Environment** carries `AGENTS_HOME` (the user store), `AGENTS_SCOPE_ROOT` (the
|
|
243
280
|
store the overlay is installed into), `AGENTS_SCOPE` (`user` or `project`) and
|
|
244
281
|
`AGENTS_OVERLAY_DIR` (the overlay's own installed dir) — never hardcode a home path.
|
|
245
|
-
- **Environment** is also the scope's assembled `dotagents env`: every overlay's `
|
|
246
|
-
on `
|
|
282
|
+
- **Environment** is also the scope's assembled `dotagents env`: every overlay's `bin/`
|
|
283
|
+
on `PATH`, and every overlay's `lib/` importable (through the venv's layering, or
|
|
284
|
+
`PYTHONPATH` without a venv).
|
|
247
285
|
- **Time limit**: 300 seconds, or the manifest's `setup_timeout`, or the command's
|
|
248
286
|
`--setup-timeout` (which wins); `0` means no limit. A script still running then is
|
|
249
287
|
stopped, and that counts as a failure (exit 124).
|
|
@@ -19,6 +19,16 @@ never lands in the public repo). `<name>` defaults to the project's basename, so
|
|
|
19
19
|
local checkout and a cloud checkout of the same project resolve to the same store
|
|
20
20
|
entry.
|
|
21
21
|
|
|
22
|
+
The store's installed overlays can travel two ways:
|
|
23
|
+
|
|
24
|
+
- **Tracked copies**: `overlays/` is committed. Every machine and cloud session has
|
|
25
|
+
them with the clone, offline; every `overlays sync` is a diff in the private repo.
|
|
26
|
+
- **A registry**: `<store>/dotagents.toml` names one source per overlay and
|
|
27
|
+
`overlays/` is left out of the repo. `dotagents overlays add '*' -g` installs
|
|
28
|
+
everything it names, keeping going past one that fails; the bootstrap below runs
|
|
29
|
+
it in a cloud session. The repo stays small; each new machine fetches the
|
|
30
|
+
overlays once.
|
|
31
|
+
|
|
22
32
|
## Commands
|
|
23
33
|
|
|
24
34
|
The overlay goes into the user store, since the store is what it syncs:
|
|
@@ -82,7 +92,8 @@ curl -fsSL https://raw.githubusercontent.com/<you>/dotagents/main/tools/cloud-se
|
|
|
82
92
|
success. `&&` propagates the curl failure instead.
|
|
83
93
|
|
|
84
94
|
The bootstrap authenticates (bypassing a hosted-runner `github.com` → proxy git
|
|
85
|
-
rewrite), clones/pulls the store, installs the CLI,
|
|
95
|
+
rewrite), clones/pulls the store, installs the CLI, installs every overlay the store's
|
|
96
|
+
registry names (`overlays add '*'`, when it has one), links the project, and wires the
|
|
86
97
|
hooks into `~/.claude/settings.json` — driven by `AGENTS_REMOTE` /
|
|
87
98
|
`DOTAGENTS_AGENTS_TOKEN` / `DOTAGENTS_CLI_INSTALL` environment variables (the token is
|
|
88
99
|
never committed). `AGENTS_OVERLAYS_REMOTE` / `AGENTS_OVERLAYS_REF` choose where it
|
|
@@ -30,10 +30,10 @@ and an error saying a command is required, and exits 2.
|
|
|
30
30
|
|
|
31
31
|
| Command | Contract |
|
|
32
32
|
| --- | --- |
|
|
33
|
-
| `init [-g] [--dest D] [--from SRC] [--bin-dir D] [--agents a,b] [--no-hooks] [--powershell-env-hook] [--force] [--dry-run]` | Merge the base block into `<store>/AGENTS.md`, write `<store>/bin/dotagents[.cmd]`, and per active agent (`--agents`, else detected + `claude`) write its include and hooks. `--force` replaces `AGENTS.md`'s content, backed up under `<store>/install_backup/<timestamp>/`. `--from` records its base in `<store>/dotagents/config.toml`. |
|
|
34
|
-
| `overlays add NAME... [-g] [--repo SPEC]... [--copy] [--no-setup] [--setup-timeout S] [--no-requires] [--prune] [--dry-run]` | Install each overlay and its `requires` into `<store>/overlays/<name>/` (an installed one is made to match its source again, as `sync` does; `--prune` clears its ignored files too), publish its skills, run its `setup.py`, recompose the managed block. Every name is resolved before anything is written; a source inside `<store>/overlays/` is refused;
|
|
35
|
-
| `overlays remove NAME... [-g] [--force] [--dry-run]` | Delete the overlay dirs, unpublish the skills they published, recompose the block. Refuses an overlay another installed overlay requires unless `--force`. No name: exit 2. |
|
|
36
|
-
| `overlays sync [GLOB] [-g] [--repo SPEC]... [--copy] [--prune] [--no-setup] [--setup-timeout S] [--dry-run]` | Refresh installed overlays from the repo recorded at install (`--repo` replaces it): the install is made to match the source exactly: new and changed files land, `overlay.toml` is refreshed, files the source does not ship are removed; a file edited here is backed up first under `<store>/install_backup/<timestamp>/overlays/<name>/`. What the `.gitignore` / `.ignore` at the overlay's root match (setup output, local state) and tool caches are left alone; `--prune` clears them too. Installs new `requires
|
|
33
|
+
| `init [-g] [--dest D] [--from SRC] [--bin-dir D] [--agents a,b] [--no-hooks] [--powershell-env-hook] [--no-venv] [--force] [--dry-run]` | Merge the base block into `<store>/AGENTS.md`, write `<store>/bin/dotagents[.cmd]`, and per active agent (`--agents`, else detected + `claude`) write its include and hooks. Then bring the scope's Python venvs up to date (`_pyvenv.sync_venvs`; a failure is a warning; not with `--dest` or `--no-venv`). `--force` replaces `AGENTS.md`'s content, backed up under `<store>/install_backup/<timestamp>/`. `--from` records its base in `<store>/dotagents/config.toml`. |
|
|
34
|
+
| `overlays add NAME\|GLOB... [-g] [--repo SPEC]... [--copy] [--no-setup] [--setup-timeout S] [--no-requires] [--no-venv] [--prune] [--dry-run]` | Install each overlay and its `requires` into `<store>/overlays/<name>/` (an installed one is made to match its source again, as `sync` does; `--prune` clears its ignored files too), publish its skills, install every overlay's `requirements.txt` into the scope venv (`_pyvenv`; not with `--no-venv`), run its `setup.py`, recompose the managed block. A glob (`'*'`, `'py*'`) stands for every name the repos offer that matches it; one matching nothing is an error. Every name is resolved before anything is written; a source inside `<store>/overlays/` is refused. An overlay whose copy, requirements or setup fail is logged and skipped, along with what requires it; the others still install, and the command exits 1 naming each failure. One this run was installing for the first time is removed again; one already installed stays. No name: exit 2. |
|
|
35
|
+
| `overlays remove NAME... [-g] [--force] [--no-venv] [--dry-run]` | Delete the overlay dirs, unpublish the skills they published, recompose the block, rewrite the venv layering (installed requirements stay). Refuses an overlay another installed overlay requires unless `--force`. No name: exit 2. |
|
|
36
|
+
| `overlays sync [GLOB] [-g] [--repo SPEC]... [--copy] [--prune] [--no-setup] [--setup-timeout S] [--no-venv] [--dry-run]` | Refresh installed overlays from the repo recorded at install (`--repo` replaces it): the install is made to match the source exactly: new and changed files land, `overlay.toml` is refreshed, files the source does not ship are removed; a file edited here is backed up first under `<store>/install_backup/<timestamp>/overlays/<name>/`. What the `.gitignore` / `.ignore` at the overlay's root match (setup output, local state) and tool caches are left alone; `--prune` clears them too. Installs new `requires`, then the venv requirements (when they changed) before each setup. Exits 1 when an overlay's repo cannot be loaded, its source lies inside `<store>/overlays/`, or its requirements or setup fail. |
|
|
37
37
|
| `overlays list [-g] [--repo SPEC]... [--json]` | Installed overlays per store (shadowed copies marked, unmet `requires` flagged) and what the repos offer. |
|
|
38
38
|
| `overlays show NAME [-g] [--repo SPEC]... [--json]` | One overlay: the copy a session would use, else the source's; manifest, setup, skills, file count, recorded source. No name: exit 2. |
|
|
39
39
|
| `context [OUT] [-g] [--agents a,b] [--format markdown\|system-reminder\|json] [--write-agent] [--inline]` | Print (or write to `OUT`) the assembled context. `--write-agent` merges it into each agent's `context_target` under the project root (not with `-g`). Exits 2 when `--agents` names no known agent. |
|
|
@@ -42,7 +42,7 @@ and an error saying a command is required, and exits 2.
|
|
|
42
42
|
| `launch [AGENT] [-g] [--command PROG] [--no-context] [--inline] [--write-agent] [--dry-run] [-- ARGS...]` | Run the agent's CLI with the env applied and the context handed over; the exit code is the harness's (`128+N` on signal N). |
|
|
43
43
|
| `findings add\|list\|show\|done\|reopen\|remove\|index\|path [-g] [--dir D]` | The findings queue at `<store>/findings/` (`--dir` overrides): one markdown file per finding, `done` moves it to `processed/` with a required resolution, `INDEX.md` regenerated on every change. The frontmatter is valid YAML (a value is double-quoted when it must be); `index --requote` fixes values written bare in existing files, touching nothing else. |
|
|
44
44
|
| `about [--json]` | `dotagents-cli <version>`, then `<distribution> <version>` per bundled (`.pyz`) or installed package. |
|
|
45
|
-
| `build-pyz [--out P] [--python SHEBANG] [--duho-version V] [--pathapi-version V] [--extras a,b]` | Build a zipapp from a source checkout; errors elsewhere. |
|
|
45
|
+
| `build-pyz [--out P] [--python SHEBANG] [--duho-version V] [--pathapi-version V] [--extras a,b] [--with-pip]` | Build a zipapp from a source checkout; errors elsewhere. `--with-pip` vendors the pinned pip wheel (`_pipwheel`) as `dotagents/_vendor/`. |
|
|
46
46
|
|
|
47
47
|
**Every command but `env` is also an MCP tool.** With `DOTAGENTS_MCP=stdio` in its
|
|
48
48
|
environment, `dotagents` serves the command set — built-in, bundled and discovered —
|
|
@@ -142,8 +142,11 @@ The package's own data; library code, importing nothing from `dotagents.cli`.
|
|
|
142
142
|
`AGENTS_MD_PLACEHOLDER = "{{AGENTS_MD}}"`.
|
|
143
143
|
- `base_agents_text(src, dest, *, project=False) -> str` — the base block for the
|
|
144
144
|
store at `dest`: the project template for a project store when the base has one,
|
|
145
|
-
else the user template, else `<src>/AGENTS.md`; `{{AGENTS_MD}}` rendered as
|
|
146
|
-
|
|
145
|
+
else the user template, else `<src>/AGENTS.md`; `{{AGENTS_MD}}` rendered as
|
|
146
|
+
`home_relative(<dest>/AGENTS.md)`, so a store synced between machines whose home
|
|
147
|
+
directories differ renders the same block.
|
|
148
|
+
- `home_relative(path) -> str` — `path` as POSIX text, `~/<rest>` when it is under
|
|
149
|
+
`Path.home()`, absolute otherwise.
|
|
147
150
|
- `pyz_archive() -> str | None` — the `.pyz` this dotagents is imported from (the
|
|
148
151
|
ancestor of the module's `__file__` that is a file), or `None` for a plain
|
|
149
152
|
install. The archive also holds the vendored duho and pathapi; `env`
|
|
@@ -384,8 +387,12 @@ proxy model.
|
|
|
384
387
|
|
|
385
388
|
- Roots: `AGENTS_HOME` and `AGENTS_PROJECT_ROOT` name the stores walked, absolute —
|
|
386
389
|
an inherited value naming the same directory holds, another is replaced; in a
|
|
387
|
-
user-scope walk `AGENTS_PROJECT_ROOT` is set only when unset.
|
|
388
|
-
|
|
390
|
+
user-scope walk `AGENTS_PROJECT_ROOT` is set only when unset. `AGENTS_PYTHON`:
|
|
391
|
+
the active scope venv's interpreter (`_pyvenv.active_venv`), else
|
|
392
|
+
`sys.executable`; it replaces an inherited value equal to `sys.executable` or
|
|
393
|
+
naming another `.pyvenv` interpreter, and any other pin holds. `AGENTS_PYVENV`:
|
|
394
|
+
that venv's dir, removed when there is none. Only when unset: one
|
|
395
|
+
`<NAME>_OVERLAY_ROOT` per
|
|
389
396
|
`scope.overlays` (a value pinned to the user store's copy is re-pointed when a
|
|
390
397
|
project copy shadows it). `AGENTS_PYLIB` (`_env.PYLIB_VAR`): the `.pyz` when
|
|
391
398
|
dotagents runs from one (`_resources.pyz_archive()`), else not set — where its
|
|
@@ -395,10 +402,11 @@ proxy model.
|
|
|
395
402
|
- `PATH`: every level's `bin` (contract A, not project-root, missing dirs included)
|
|
396
403
|
at the front in that order, whatever the caller's `PATH` held; empty and
|
|
397
404
|
cwd-relative inherited entries are dropped.
|
|
398
|
-
- `PYTHONPATH`: every existing level's `lib`
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
removed
|
|
405
|
+
- `PYTHONPATH`: every existing level's `lib` the active venv's `.pth` does not
|
|
406
|
+
already layer, at the front, highest precedence first (with a venv synced for the
|
|
407
|
+
scope, none); the entries an inherited `AGENTS_PYTHONPATH` named (another scope's
|
|
408
|
+
libs) are removed first. `AGENTS_PYTHONPATH`: every existing `lib`,
|
|
409
|
+
`os.pathsep`-joined, layered or not; removed when there are none.
|
|
402
410
|
- Env files: all `pre.env.py` / `pre.env` (+ the project store's `pre.local.env`),
|
|
403
411
|
then all `env.py` / `env` (+ `local.env`), contract-A order, regular files only,
|
|
404
412
|
each evaluated against everything before it. The project root contributes none.
|
|
@@ -444,7 +452,8 @@ API:
|
|
|
444
452
|
- `ENV_CACHE_TTL = 300.0` (seconds). `env_cache_key(scope, base_env, *parts) -> str`
|
|
445
453
|
— a digest of what an assembly reads without running it: roots, cwd, interpreter,
|
|
446
454
|
package version, installed overlays, each env-file candidate's
|
|
447
|
-
existence/mtime/size, every file under an existing `lib`,
|
|
455
|
+
existence/mtime/size, every file under an existing `lib`, each store's venv state
|
|
456
|
+
file, the whole `base_env`,
|
|
448
457
|
and `parts` (format, mode). `read_env_cache(scope, key, *, now=None) ->
|
|
449
458
|
Optional[str]` (None when absent or older than the TTL); `write_env_cache(scope,
|
|
450
459
|
key, text) -> None` (owner-only, under `<user store>/.cache/env/`; never raises).
|
|
@@ -462,7 +471,9 @@ API:
|
|
|
462
471
|
and `AGENTS.local.md` (project store and project root), each prefixed
|
|
463
472
|
`<!-- Source: <path> -->`. Then a skills listing (`- **name** (`<SKILL.md>`):
|
|
464
473
|
description`, from each skill's leading frontmatter; a project skill wins), then
|
|
465
|
-
a "Local additions to overlay files" section when `local_additions` finds any
|
|
474
|
+
a "Local additions to overlay files" section when `local_additions` finds any,
|
|
475
|
+
then, with `expand_vars`, the line ``Python for skills (`$AGENTS_PYTHON`): `<path>` ``
|
|
476
|
+
(`skills_python`).
|
|
466
477
|
`<PROJECT_ROOT>` and `<NAME_OVERLAY_ROOT>` placeholders expand; with
|
|
467
478
|
`expand_vars` so do `$NAME_OVERLAY_ROOT` / `${NAME_OVERLAY_ROOT}`. `inline`
|
|
468
479
|
appends the on-demand `.md` files the sources reference, each resolved against
|
|
@@ -470,8 +481,10 @@ API:
|
|
|
470
481
|
system source never into the project).
|
|
471
482
|
- `assemble_context_data(agent, scope, *, inline=False, expand_vars=True) -> dict`
|
|
472
483
|
— `{"agent", "harness", "sources", "context", "skills": [{"name",
|
|
473
|
-
"description", "path"}], "local_additions": [{"overlay_file", "local": [...]}]
|
|
474
|
-
`context` without the skills and local-additions listings.
|
|
484
|
+
"description", "path"}], "local_additions": [{"overlay_file", "local": [...]}],
|
|
485
|
+
"python"}`; `context` without the skills and local-additions listings.
|
|
486
|
+
- `skills_python(scope) -> str` — the active scope venv's interpreter, else
|
|
487
|
+
`sys.executable`.
|
|
475
488
|
- `local_additions(scope) -> list[tuple[Path, list[Path]]]` — the user's own
|
|
476
489
|
additions to installed overlay files: for each `.md` an overlay in `scope.overlays`
|
|
477
490
|
ships in a subdirectory other than `skills/`, every store's file at the same
|
|
@@ -675,6 +688,62 @@ objects `{"matcher"?: str, "hooks": [{"type": "command", "command": str, ...}]}`
|
|
|
675
688
|
- `check_path_warning(bin_dir) -> Optional[str]` — a warning with the PATH line to
|
|
676
689
|
add, or `None` when `bin_dir` is on `PATH`.
|
|
677
690
|
|
|
691
|
+
## `dotagents._pyvenv`
|
|
692
|
+
|
|
693
|
+
One venv per store, `<store>/.pyvenv/<X.Y.Z>-<os>-<arch>/`, made from the running
|
|
694
|
+
interpreter; layered project > user > system through a `.pth`. `.pyvenv/` holds the
|
|
695
|
+
agents' venvs only (skills, overlay helpers, setup scripts), never a project's own
|
|
696
|
+
code. `AGENTS_NO_PYVENV=1` (or `true`/`yes`/`on`) turns it all off.
|
|
697
|
+
|
|
698
|
+
- `BASE_REQUIREMENTS = ("duho>=0.7.5,<0.8",)` — always in the user venv; dotagents'
|
|
699
|
+
own duho range. `REQUIREMENTS_FILE = "requirements.txt"` (at an overlay's root),
|
|
700
|
+
`PYVENV_DIR = ".pyvenv"`, `STATE_FILE = ".dotagents-venv.json"` (in the venv:
|
|
701
|
+
`{"digest", "requirements", "pth"}`), `PTH_FILE = "dotagents-layers.pth"` (in its
|
|
702
|
+
site-packages), `DISABLE_ENV = "AGENTS_NO_PYVENV"`.
|
|
703
|
+
- `sync_venvs(scope, *, dry_run=False, logger=None) -> list[Path]` — the user venv
|
|
704
|
+
(base requirements + the user store's overlays' `requirements.txt`), then the
|
|
705
|
+
project's when `wants_venv` (its own overlays' requirements only). pip runs only
|
|
706
|
+
when the requirements' digest changed, in one `pip install -r ... -r ...` per
|
|
707
|
+
venv, with `--find-links` from `AGENTS_PIP_SOURCE`. The `.pth` is rewritten when
|
|
708
|
+
it differs: the store's own libs, then each lower store's venv site-packages and
|
|
709
|
+
libs, then `runtime_entry()`. Raises `VenvError` (a `SystemExit`) on failure.
|
|
710
|
+
- `wants_venv(scope, level, store, libs) -> bool` — always for `user`; for `project`
|
|
711
|
+
when it has overlay requirements or libs; never for `system` (a venv an
|
|
712
|
+
administrator made there is still layered).
|
|
713
|
+
- `ensure_venv(target, python=None, *, with_pip=None, dry_run=False, logger=None)
|
|
714
|
+
-> Optional[Path]` — the venv's interpreter, created when missing; `with_pip=None`
|
|
715
|
+
tries ensurepip and falls back to `--without-pip`, `False` never uses it.
|
|
716
|
+
- `pip_command(vpy, *, cache_dir, logger=None) -> list[str]` — the venv's own
|
|
717
|
+
`-m pip`, else `[sys.executable, <pip wheel>/pip, "--python", <vpy>]`.
|
|
718
|
+
- `active_venv(scope, environ=None) -> Optional[Path]` — the highest store's venv
|
|
719
|
+
for the running interpreter that a sync completed (its `STATE_FILE` exists); a
|
|
720
|
+
venv made there any other way is never an agents venv.
|
|
721
|
+
- `layers(scope) -> list[tuple[str, Path, list[Path]]]` — `(level, store, libs)`,
|
|
722
|
+
highest first. `requirement_files(scope, store) -> list[Path]`.
|
|
723
|
+
`runtime_entry() -> str` (the `.pyz`, else the dir holding `dotagents`).
|
|
724
|
+
`venv_dir(store)`, `venv_python(venv)`, `site_packages(venv)`, `triplet()`,
|
|
725
|
+
`os_bucket()`, `read_state(venv)`, `disabled(environ=None)`,
|
|
726
|
+
`is_pyvenv_python(path)`.
|
|
727
|
+
|
|
728
|
+
## `dotagents._pipwheel`
|
|
729
|
+
|
|
730
|
+
The pip wheel for a venv with no pip of its own.
|
|
731
|
+
|
|
732
|
+
- `PIP_VERSION = "25.3"` (the last pip for Python 3.9), `PIP_WHEEL`, `PIP_SHA256` —
|
|
733
|
+
every source must match the hash. `PIP_SOURCE_ENV = "AGENTS_PIP_SOURCE"`.
|
|
734
|
+
`VENDORED = ("_vendor", PIP_WHEEL)` (inside the package),
|
|
735
|
+
`DEFAULT_INDEX = "https://pypi.org/simple"`.
|
|
736
|
+
- `pip_wheel(cache_dir, *, logger=None, environ=None) -> Path` — from, in order: the
|
|
737
|
+
cache file, the vendored copy (`build-pyz --with-pip`), `AGENTS_PIP_SOURCE` and pip's
|
|
738
|
+
`find-links` (a dir, `file:`/`http(s):`, or a pathapi-uri URI), then the index
|
|
739
|
+
(`PIP_INDEX_URL`, else pip's config `index-url`, else PyPI; PEP 691 JSON, else PEP
|
|
740
|
+
503 HTML), honouring pip's `cert`, `trusted-host`, `proxy` and credentials in the
|
|
741
|
+
URL. Raises `PipUnavailable` (a `SystemExit`) naming every source, redacted.
|
|
742
|
+
- `find_links(environ=None, *, cache_dir, logger=None) -> list[str]` —
|
|
743
|
+
`AGENTS_PIP_SOURCE` for pip's `--find-links`, a URI pip cannot read copied locally.
|
|
744
|
+
- `pip_config(environ=None) -> dict[str, str]` — `index-url`, `find-links`, `cert`,
|
|
745
|
+
`trusted-host`, `proxy` from `PIP_*` over pip's config files.
|
|
746
|
+
|
|
678
747
|
## `dotagents._fs`
|
|
679
748
|
|
|
680
749
|
- `write_text_lf(path, text, *, atomic=False) -> Path` — UTF-8, LF line endings on
|
|
@@ -705,8 +774,12 @@ Read:
|
|
|
705
774
|
- `AGENTS_OVERLAYS_REPO`, `AGENTS_OVERLAYS_REPO_<KEY>` — overlay repos (after
|
|
706
775
|
`--repo`). `AGENTS_CMDS_PATH` — extra command dirs.
|
|
707
776
|
- `AGENTS_HARNESS` — the running harness (registry name or harness id), for
|
|
708
|
-
identity. `AGENTS_PYTHON` — the interpreter for `env.py
|
|
709
|
-
the overlay/store `lib` dirs
|
|
777
|
+
identity. `AGENTS_PYTHON` — the interpreter for `env.py` and `setup.py`.
|
|
778
|
+
`AGENTS_PYTHONPATH` — the overlay/store `lib` dirs, highest precedence first.
|
|
779
|
+
`AGENTS_NO_PYVENV` — turns the scope venvs off. `AGENTS_PIP_SOURCE` — a directory
|
|
780
|
+
of wheels (or a URI to one) for pip, before the index. `PIP_INDEX_URL`,
|
|
781
|
+
`PIP_CONFIG_FILE`, `PIP_FIND_LINKS`, `PIP_CERT`, `PIP_TRUSTED_HOST`, `PIP_PROXY` and
|
|
782
|
+
pip's config files — read to fetch the pip wheel.
|
|
710
783
|
`AGENTS_PYLIB` — the `.pyz` dotagents runs from (duho and pathapi import
|
|
711
784
|
from it), unset for an installed dotagents.
|
|
712
785
|
- Harness config dirs: `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, `PI_CODING_AGENT_DIR`.
|
|
@@ -722,7 +795,7 @@ Read:
|
|
|
722
795
|
|
|
723
796
|
Emitted by `env` (and applied by `launch`): `AGENTS_HARNESS`, `AGENTS_VENDOR`,
|
|
724
797
|
`AGENT`, `AGENTS_MODEL`, `AGENTS_HOME`, `AGENTS_PROJECT_ROOT`, `AGENTS_PYTHON`,
|
|
725
|
-
`AGENTS_PYLIB` (from a `.pyz` only), `<NAME>_OVERLAY_ROOT`, `PATH`, `AGENTS_PYTHONPATH`, `AGENTS_PROXY` and the mirrored
|
|
798
|
+
`AGENTS_PYVENV` (with a scope venv), `AGENTS_PYLIB` (from a `.pyz` only), `<NAME>_OVERLAY_ROOT`, `PATH`, `AGENTS_PYTHONPATH`, `AGENTS_PROXY` and the mirrored
|
|
726
799
|
proxy vars, plus whatever the env files set. `AGENTS_AGENT` is never emitted.
|
|
727
800
|
`launch` also exports `AGENTS_CONTEXT_FILE`.
|
|
728
801
|
|
|
@@ -739,6 +812,9 @@ Set for an overlay's `setup.py`: `AGENTS_HOME` (user store), `AGENTS_SCOPE_ROOT`
|
|
|
739
812
|
scratch dir removed at exit); `duho` reads the command modules' flags and help
|
|
740
813
|
through the zip importer.
|
|
741
814
|
- **Writes are LF-only.** Use `_fs.write_text_lf`, never `Path.write_text`.
|
|
815
|
+
- **Skills run under `AGENTS_PYTHON`**, the scope venv: duho, every overlay's
|
|
816
|
+
requirements and libs, and dotagents import there. Its site-packages is never put
|
|
817
|
+
on `PYTHONPATH`, which every other Python in the session would read first.
|
|
742
818
|
- **`env` output is sensitive**: it prints resolved values. Nothing in the package
|
|
743
819
|
logs a value, only names.
|
|
744
820
|
- **Credentials in a repo URL** are removed from every log line, cache dir name and
|
|
@@ -463,9 +463,23 @@ def assemble_context(
|
|
|
463
463
|
return ""
|
|
464
464
|
text += _get_skills_listing(scope)
|
|
465
465
|
text += _get_local_additions_listing(scope)
|
|
466
|
+
if expand_vars: # a machine path: never into a file that may be committed
|
|
467
|
+
text += "\n\nPython for skills (`$AGENTS_PYTHON`): `%s`\n" % skills_python(scope)
|
|
466
468
|
return text
|
|
467
469
|
|
|
468
470
|
|
|
471
|
+
def skills_python(scope: _scope.Scope) -> str:
|
|
472
|
+
"""The interpreter skills run with: the scope venv's (`dotagents._pyvenv`),
|
|
473
|
+
which imports duho, every overlay's requirements and every overlay lib;
|
|
474
|
+
else the one running dotagents."""
|
|
475
|
+
import sys
|
|
476
|
+
|
|
477
|
+
from dotagents import _pyvenv
|
|
478
|
+
|
|
479
|
+
venv = _pyvenv.active_venv(scope)
|
|
480
|
+
return str(_pyvenv.venv_python(venv)) if venv is not None else sys.executable
|
|
481
|
+
|
|
482
|
+
|
|
469
483
|
def assemble_context_data(
|
|
470
484
|
agent: _agents.Agent, scope: _scope.Scope, *, inline: bool = False,
|
|
471
485
|
expand_vars: bool = True,
|
|
@@ -480,6 +494,7 @@ def assemble_context_data(
|
|
|
480
494
|
"context": <assembled markdown text, minus the skills listing>,
|
|
481
495
|
"skills": [{"name": ..., "description": ..., "path": <SKILL.md>}, ...],
|
|
482
496
|
"local_additions": [{"overlay_file": ..., "local": [<path>, ...]}, ...],
|
|
497
|
+
"python": <the interpreter skills run with, see skills_python>,
|
|
483
498
|
}
|
|
484
499
|
``context`` is the same assembled(+inlined, with ``inline=True``) text the
|
|
485
500
|
markdown format emits, but WITHOUT the skills and local-additions listings
|
|
@@ -501,4 +516,5 @@ def assemble_context_data(
|
|
|
501
516
|
{"overlay_file": str(path), "local": [str(p) for p in found]}
|
|
502
517
|
for path, found in local_additions(scope)
|
|
503
518
|
],
|
|
519
|
+
"python": skills_python(scope),
|
|
504
520
|
}
|
|
@@ -1054,7 +1054,24 @@ def get_environment(
|
|
|
1054
1054
|
# a venv's, or absent, while this one demonstrably runs the CLI.
|
|
1055
1055
|
# `sys.executable` is '' or None under an embedding host: then nothing is
|
|
1056
1056
|
# exported rather than an empty command name.
|
|
1057
|
-
|
|
1057
|
+
# With a scope venv (`_pyvenv`) it is that venv's interpreter instead: it
|
|
1058
|
+
# sees every overlay lib and requirement through its .pth layering. It
|
|
1059
|
+
# replaces an inherited value this code would have set (the bare
|
|
1060
|
+
# interpreter, or another scope's venv); any other pin holds.
|
|
1061
|
+
from dotagents import _pyvenv
|
|
1062
|
+
|
|
1063
|
+
venv = _pyvenv.active_venv(scope, osenv)
|
|
1064
|
+
python = str(_pyvenv.venv_python(venv)) if venv is not None else sys.executable
|
|
1065
|
+
pinned = osenv.get("AGENTS_PYTHON")
|
|
1066
|
+
if python and pinned != python and (
|
|
1067
|
+
not pinned or pinned == sys.executable or _pyvenv.is_pyvenv_python(pinned)
|
|
1068
|
+
):
|
|
1069
|
+
_apply({"AGENTS_PYTHON": python})
|
|
1070
|
+
if venv is not None:
|
|
1071
|
+
if osenv.get("AGENTS_PYVENV") != str(venv):
|
|
1072
|
+
_apply({"AGENTS_PYVENV": str(venv)})
|
|
1073
|
+
elif "AGENTS_PYVENV" in osenv:
|
|
1074
|
+
_apply(EnvChanges(removed=["AGENTS_PYVENV"]))
|
|
1058
1075
|
# --- AGENTS_PYLIB --- where dotagents' own libraries (duho, pathapi)
|
|
1059
1076
|
# import from for an overlay that builds on them. Set only when dotagents
|
|
1060
1077
|
# runs from a .pyz: the archive, importable by zipimport. An installed
|
|
@@ -1117,8 +1134,15 @@ def get_environment(
|
|
|
1117
1134
|
e for e in inherited.split(os.pathsep)
|
|
1118
1135
|
if e and os.path.normcase(e) not in stale
|
|
1119
1136
|
]
|
|
1137
|
+
# A lib the scope venv's .pth already layers stays off PYTHONPATH: the
|
|
1138
|
+
# venv's interpreter (AGENTS_PYTHON) imports it anyway, and no other
|
|
1139
|
+
# Python in the session should. AGENTS_PYTHONPATH still names them all.
|
|
1140
|
+
layered = {
|
|
1141
|
+
os.path.normcase(e) for e in (_pyvenv.read_state(venv).get("pth") or [] if venv else [])
|
|
1142
|
+
}
|
|
1143
|
+
on_path = [p for p in lib_paths if os.path.normcase(p) not in layered]
|
|
1120
1144
|
pythonpath = _prepended_path_var({"PYTHONPATH": os.pathsep.join(kept)}, "PYTHONPATH",
|
|
1121
|
-
list(reversed(
|
|
1145
|
+
list(reversed(on_path)))
|
|
1122
1146
|
if pythonpath is None:
|
|
1123
1147
|
pythonpath = os.pathsep.join(kept)
|
|
1124
1148
|
if pythonpath != inherited:
|
|
@@ -1187,6 +1211,12 @@ def get_diff(
|
|
|
1187
1211
|
#: store, the clock), so its output is re-derived at least this often.
|
|
1188
1212
|
ENV_CACHE_TTL = 300.0
|
|
1189
1213
|
|
|
1214
|
+
#: How far in the future a cache file's mtime may be and still count as fresh.
|
|
1215
|
+
#: On Windows before Python 3.13 ``time.time()`` reads a clock that ticks every
|
|
1216
|
+
#: ~15.6 ms while NTFS stamps files from a precise one, so a file read back at
|
|
1217
|
+
#: once can be dated slightly after "now". Beyond this, the clock moved back.
|
|
1218
|
+
_ENV_CACHE_CLOCK_SLACK = 2.0
|
|
1219
|
+
|
|
1190
1220
|
#: Every env-file name the two tiers resolve (see :func:`resolve_env_files`).
|
|
1191
1221
|
_ENV_FILE_NAMES = (
|
|
1192
1222
|
{"default": "pre.env.py", "project-root": ""},
|
|
@@ -1244,6 +1274,13 @@ def env_cache_key(scope: Scope, base_env: "dict[str, str]", *parts: str) -> str:
|
|
|
1244
1274
|
items.append("lib %s %s" % (path, _stat_sig(path)))
|
|
1245
1275
|
if path.is_dir():
|
|
1246
1276
|
items += _tree_sig(path)
|
|
1277
|
+
# A venv sync (`_pyvenv`) changes AGENTS_PYTHON and what stays off PYTHONPATH.
|
|
1278
|
+
from dotagents import _pyvenv
|
|
1279
|
+
|
|
1280
|
+
items += [
|
|
1281
|
+
"venv %s %s" % (store, _stat_sig(_pyvenv.venv_dir(store) / _pyvenv.STATE_FILE))
|
|
1282
|
+
for store in scope.stores
|
|
1283
|
+
]
|
|
1247
1284
|
items += sorted("%s=%s" % kv for kv in base_env.items())
|
|
1248
1285
|
h = hashlib.sha256()
|
|
1249
1286
|
for item in items:
|
|
@@ -1263,7 +1300,7 @@ def read_env_cache(scope: Scope, key: str, *, now: "Optional[float]" = None) ->
|
|
|
1263
1300
|
path = _env_cache_dir(scope) / key
|
|
1264
1301
|
try:
|
|
1265
1302
|
age = (time.time() if now is None else now) - os.stat(str(path)).st_mtime
|
|
1266
|
-
if age <
|
|
1303
|
+
if age < -_ENV_CACHE_CLOCK_SLACK or age >= ENV_CACHE_TTL:
|
|
1267
1304
|
return None
|
|
1268
1305
|
with open(str(path), encoding="utf-8", newline="") as fh:
|
|
1269
1306
|
return fh.read()
|
{dotagents_cli-0.7.6 → dotagents_cli-0.8.0}/src/dotagents/_overlay/dotagents/templates/AGENTS.md
RENAMED
|
@@ -30,6 +30,13 @@ Startup: annotate that you read `{{AGENTS_MD}}`.
|
|
|
30
30
|
`kb/` file routed from "Load on demand"), or decide no change is needed — and
|
|
31
31
|
closes it with `dotagents findings done -g <name> -r "<resolution>"` (moved,
|
|
32
32
|
never deleted; the resolution is the record).
|
|
33
|
+
- **Python for skills**: run every skill script, overlay `bin/` helper and anything
|
|
34
|
+
importing an overlay's `lib/` with `$AGENTS_PYTHON` (PowerShell
|
|
35
|
+
`& $env:AGENTS_PYTHON`), never a bare `python`, `python3` or `py`. It is the scope's
|
|
36
|
+
venv: duho, every overlay's requirements and every overlay `lib/` (project, then
|
|
37
|
+
user, then system) import there and nowhere else. When the variable is unset, use
|
|
38
|
+
the interpreter `dotagents context` prints. `.agents/.pyvenv/` holds only these
|
|
39
|
+
agents' venvs: never create, install into or test a project in one.
|
|
33
40
|
- **This file**: everything between the `dotagents:begin`/`dotagents:end` markers is
|
|
34
41
|
managed — `dotagents init` refreshes it and leaves anything outside untouched. Add
|
|
35
42
|
your own rules and routing below the end marker, not inside.
|