dotagents-cli 0.6.2__tar.gz → 0.7.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.6.2 → dotagents_cli-0.7.0}/CHANGELOG.md +57 -1
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/PKG-INFO +8 -8
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/README.md +7 -7
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/guide/commands.md +35 -16
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/guide/install.md +1 -1
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/guide/overlays.md +8 -4
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/index.md +2 -1
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/AGENTS.md +58 -15
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/__init__.py +1 -1
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_agents.py +25 -6
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_env.py +22 -2
- dotagents_cli-0.7.0/src/dotagents/_ignore.py +146 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_overlays.py +90 -59
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_resources.py +12 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/cli/__init__.py +23 -2
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/cli/env.py +77 -3
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/cli/overlays.py +32 -33
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_cli_main.py +2 -2
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_cmds_discovery.py +38 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_env.py +37 -0
- dotagents_cli-0.7.0/tests/test_env_into.py +89 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_fix_overlays.py +59 -20
- dotagents_cli-0.7.0/tests/test_ignore.py +58 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_overlays_cli.py +5 -10
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_overlays_command.py +7 -5
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_wire_hooks.py +35 -8
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tools/pyz_smoke.sh +7 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/.gitignore +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/LICENSE +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/agents.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/cli.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/commands.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/context.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/env.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/fs.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/hooks.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/merge.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/overlays.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/reference.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/resources.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/scope.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/skills.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/sources.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/api/wrappers.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/changelog.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/guide/authoring.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/docs/guide/private-sync.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/install.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/mkdocs.yml +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/pyproject.toml +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/__main__.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_context.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_fs.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_hooks.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_merge.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_overlay/dotagents/cmds/findings.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_overlay/dotagents/cmds/launch.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_overlay/dotagents/hooks/preinvocation_antigravity_context.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_overlay/dotagents/hooks/pretooluse_codex_env.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_overlay/dotagents/hooks/sessionstart_codex_context.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_overlay/dotagents/templates/AGENTS.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_overlay/dotagents/templates/PROJECT.md +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_scope.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_skills.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_sources.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/_wrappers.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/cli/_common.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/cli/about.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/cli/build_pyz.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/cli/context.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/cli/init.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/cli/path.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/src/dotagents/py.typed +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/_helpers.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/_shell.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/conftest.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_about.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_agents.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_api_header.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_audit_leak.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_build_pyz.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_cloud_setup.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_context.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_env_cli_scope.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_env_format.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_env_regressions.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_env_safety.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_findings_cmd.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_fix_adapters.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_fix_cli.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_fix_env.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_fix_hooks.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_fix_init.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_fix_packaging.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_fix_scope_context.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_fix_skills_adapters.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_hooks.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_init_base.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_last_mile.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_launch_cmd.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_mcp.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_overlay_libs.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_path_timeout_frontmatter.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_powershell_env_hook.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_review_security.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_scope.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_sources.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_sources_uri.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tests/test_wrappers.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tools/audit.py +0 -0
- {dotagents_cli-0.6.2 → dotagents_cli-0.7.0}/tools/cloud-setup.sh +0 -0
|
@@ -7,6 +7,60 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.7.0] - 2026-10-01
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `overlays sync`, and `overlays add` of an overlay already installed, make the
|
|
15
|
+
install exactly what the source ships: changed files are replaced and files the
|
|
16
|
+
source does not ship are removed, including ones edited or added in the install
|
|
17
|
+
(each backed up under `<store>/install_backup/` first). What the `.gitignore` /
|
|
18
|
+
`.ignore` at the overlay's root match (read as git reads a `.gitignore`; one in a
|
|
19
|
+
subdirectory is an ordinary file), and tool caches, are the install's own and left
|
|
20
|
+
alone. Previously an edited file was kept unless `--overwrite`.
|
|
21
|
+
- `--prune` (on `sync`, and now on `add`) clears what `.gitignore` / `.ignore`
|
|
22
|
+
protect and the tool caches too, leaving exactly the upstream files.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- A command module whose class declares no `_parsername_` is named by its
|
|
27
|
+
class in kebab case again (`LeakCheck` -> `dotagents leak-check`). Since 0.6.2
|
|
28
|
+
(duho 0.6.0) such a command was only reachable as `dotagents LeakCheck`.
|
|
29
|
+
- The Claude Code CwdChanged hook keeps one `AGENTS_PROJECT_ROOT` pin in
|
|
30
|
+
`$CLAUDE_ENV_FILE`, replacing the previous one, instead of appending a line on
|
|
31
|
+
every `cd` (the file is inlined into every Bash command). Other lines in the file
|
|
32
|
+
are kept. Re-run `dotagents init -g` to update an installed hook.
|
|
33
|
+
|
|
34
|
+
### Removed
|
|
35
|
+
|
|
36
|
+
- `overlays sync --overwrite`: replacing is what `sync` always does now.
|
|
37
|
+
|
|
38
|
+
## [0.6.3] - 2026-09-30
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- `env --into FILE` writes the output into FILE as the one block `env` owns
|
|
43
|
+
there, replacing the block an earlier run wrote and keeping every other line.
|
|
44
|
+
- With `--diff --format export`, a `PATH` that is the caller's own with entries
|
|
45
|
+
put in front is written as `export PATH='<entries>'"${PATH:+:$PATH}"`, so it
|
|
46
|
+
stays short and keeps what the sourcing shell has.
|
|
47
|
+
- When `dotagents` runs from a `.pyz`, `env` exports `AGENTS_PYLIB`, the path
|
|
48
|
+
of that archive. The libraries it bundles (duho, pathlib_next) import from
|
|
49
|
+
it, so an overlay built on duho works even when the interpreter in
|
|
50
|
+
`AGENTS_PYTHON` has no duho installed. An installed `dotagents` sets nothing:
|
|
51
|
+
its libraries are already importable from `AGENTS_PYTHON`. The archive is
|
|
52
|
+
never put on `PYTHONPATH`, where it would shadow a project's own copy; a
|
|
53
|
+
consumer adds it to `sys.path` itself when its import fails.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- The Claude Code SessionStart hook no longer appends the whole environment to
|
|
58
|
+
`$CLAUDE_ENV_FILE` every time it runs (startup, resume, compact, clear). Claude
|
|
59
|
+
Code inlines that file into every Bash command, and once it passed about 8 KB,
|
|
60
|
+
Git for Windows' bash truncated the command and every Bash call failed with an
|
|
61
|
+
unterminated quote. The hook now uses `env --into`, which keeps one block.
|
|
62
|
+
Re-run `dotagents init -g` to update an installed hook.
|
|
63
|
+
|
|
10
64
|
## [0.6.2] - 2026-09-28
|
|
11
65
|
|
|
12
66
|
### Added
|
|
@@ -1308,7 +1362,9 @@ Patch release: the PATH/POSIX-conversion fix above (the only change since 0.3.0)
|
|
|
1308
1362
|
affected module sources (`dotagents.cli`, `duho.presets`) to extracted temp files
|
|
1309
1363
|
before dispatch; a no-op for a plain install.
|
|
1310
1364
|
|
|
1311
|
-
[Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.
|
|
1365
|
+
[Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.7.0...HEAD
|
|
1366
|
+
[0.7.0]: https://github.com/jose-pr/dotagents/compare/v0.6.3...v0.7.0
|
|
1367
|
+
[0.6.3]: https://github.com/jose-pr/dotagents/compare/v0.6.2...v0.6.3
|
|
1312
1368
|
[0.6.2]: https://github.com/jose-pr/dotagents/compare/v0.6.1...v0.6.2
|
|
1313
1369
|
[0.6.1]: https://github.com/jose-pr/dotagents/compare/v0.6.0...v0.6.1
|
|
1314
1370
|
[0.6.0]: https://github.com/jose-pr/dotagents/compare/v0.5.1...v0.6.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: dotagents-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.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
|
|
@@ -203,14 +203,14 @@ installed first, its `routing`/`rules` merge into `AGENTS.md`'s managed block, a
|
|
|
203
203
|
`skills/<name>/` are symlinked (or `--copy`'d, for Windows / no-symlink) into the
|
|
204
204
|
store's shared `skills/` so every agent sees the same skills.
|
|
205
205
|
|
|
206
|
-
- `add` and `sync`
|
|
207
|
-
|
|
208
|
-
|
|
206
|
+
- `add` and `sync` keep an installed overlay exactly as its source ships it: changed
|
|
207
|
+
files are replaced and files the source does not ship are removed, anything edited
|
|
208
|
+
there backed up under `<store>/install_backup/` first. What the `.gitignore` /
|
|
209
|
+
`.ignore` at the overlay's root match (setup output, local state) and tool caches are left
|
|
210
|
+
alone; `--prune` clears them too. A fresh `add` whose setup script fails is rolled
|
|
211
|
+
back.
|
|
209
212
|
- `sync` refreshes each overlay from the repo it was installed from (`--repo` replaces
|
|
210
|
-
that source),
|
|
211
|
-
`requires` added upstream, and re-merges the managed block. `--overwrite` also
|
|
212
|
-
replaces edited files and `--prune` removes edited files the source dropped; both
|
|
213
|
-
back each file up under `<store>/install_backup/` first.
|
|
213
|
+
that source), installs a `requires` added upstream, and re-merges the managed block.
|
|
214
214
|
- `remove` deletes the overlay's directory, unpublishes only the skills **it**
|
|
215
215
|
published, and recomposes `AGENTS.md`'s managed block over the overlays that remain,
|
|
216
216
|
so its rules and routing leave with it. It refuses an overlay another installed
|
|
@@ -153,14 +153,14 @@ installed first, its `routing`/`rules` merge into `AGENTS.md`'s managed block, a
|
|
|
153
153
|
`skills/<name>/` are symlinked (or `--copy`'d, for Windows / no-symlink) into the
|
|
154
154
|
store's shared `skills/` so every agent sees the same skills.
|
|
155
155
|
|
|
156
|
-
- `add` and `sync`
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
- `add` and `sync` keep an installed overlay exactly as its source ships it: changed
|
|
157
|
+
files are replaced and files the source does not ship are removed, anything edited
|
|
158
|
+
there backed up under `<store>/install_backup/` first. What the `.gitignore` /
|
|
159
|
+
`.ignore` at the overlay's root match (setup output, local state) and tool caches are left
|
|
160
|
+
alone; `--prune` clears them too. A fresh `add` whose setup script fails is rolled
|
|
161
|
+
back.
|
|
159
162
|
- `sync` refreshes each overlay from the repo it was installed from (`--repo` replaces
|
|
160
|
-
that source),
|
|
161
|
-
`requires` added upstream, and re-merges the managed block. `--overwrite` also
|
|
162
|
-
replaces edited files and `--prune` removes edited files the source dropped; both
|
|
163
|
-
back each file up under `<store>/install_backup/` first.
|
|
163
|
+
that source), installs a `requires` added upstream, and re-merges the managed block.
|
|
164
164
|
- `remove` deletes the overlay's directory, unpublishes only the skills **it**
|
|
165
165
|
published, and recomposes `AGENTS.md`'s managed block over the overlays that remain,
|
|
166
166
|
so its rules and routing leave with it. It refuses an overlay another installed
|
|
@@ -87,8 +87,8 @@ the store's, else `dotagents` on `PATH`.
|
|
|
87
87
|
|
|
88
88
|
| Hook | Command | Why |
|
|
89
89
|
| --- | --- | --- |
|
|
90
|
-
| `SessionStart` |
|
|
91
|
-
| `CwdChanged` | when the new directory has a `.agents/`,
|
|
90
|
+
| `SessionStart` | writes `dotagents env --diff --format export` into `$CLAUDE_ENV_FILE` (`--into`: one block, replaced on every run; `PATH` as a prefix on the shell's own), then runs `dotagents context` | Claude sources `$CLAUDE_ENV_FILE` before each Bash command, so the env layers reach every command in the session; and it injects the hook's **stdout into the session context**, which is how the assembled context reaches the model. |
|
|
91
|
+
| `CwdChanged` | when the new directory has a `.agents/`, writes `export AGENTS_PROJECT_ROOT=<it>` into `$CLAUDE_ENV_FILE`, replacing the pin an earlier `cd` wrote; then prints the directory's `AGENTS.md` if there is one | Re-pins the project root after a `cd` into another project, and surfaces that directory's `AGENTS.md`. |
|
|
92
92
|
|
|
93
93
|
On Windows each event gets a second, PowerShell-native handler (`shell:
|
|
94
94
|
"powershell"`) that runs only when Claude Code would find no Git Bash, so a machine
|
|
@@ -105,11 +105,16 @@ without a prompt on each one requires `permissionDecision: "allow"`, which skips
|
|
|
105
105
|
approval prompt (your deny and ask rules still apply). It is off by default, and a
|
|
106
106
|
plain `init` removes one an earlier release wired.
|
|
107
107
|
|
|
108
|
-
The env half
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
The env half never truncates the file and is guarded by `[ -n "$CLAUDE_ENV_FILE" ]`
|
|
109
|
+
(see the [hooks docs](https://code.claude.com/docs/en/hooks#persist-environment-variables)):
|
|
110
|
+
another hook may write to the same file, so each hook replaces only its own part --
|
|
111
|
+
SessionStart its `env --into` block, CwdChanged its one `AGENTS_PROJECT_ROOT` line --
|
|
112
|
+
and keeps every other line. Appending instead grew the file on every re-run (resume,
|
|
113
|
+
compact, clear) and every `cd`, and Claude Code inlines it into each Bash command, which
|
|
114
|
+
Git for Windows' bash cuts off at about 8 KB. Each run starts from a fresh environment
|
|
115
|
+
(the hooks docs: previously sourced env files are not loaded in the hook's process), so
|
|
116
|
+
SessionStart recomputes the whole diff: a value changed since the last run is updated,
|
|
117
|
+
and one no env layer sets any more drops out. `$CLAUDE_ENV_FILE` exists only inside SessionStart/Setup/CwdChanged/FileChanged
|
|
113
118
|
hook processes — it is absent from the session's own shell, so checking for it with
|
|
114
119
|
`env | grep` proves nothing.
|
|
115
120
|
|
|
@@ -163,7 +168,7 @@ Manages opt-in overlays **by name**. See [Overlays](overlays.md) for the full mo
|
|
|
163
168
|
dotagents overlays add python engineering # install into the scope, publish skills, merge rules/routing
|
|
164
169
|
dotagents overlays list # installed (discovered) + available from the repos
|
|
165
170
|
dotagents overlays sync 'py*' # refresh installed overlays matching a glob
|
|
166
|
-
dotagents overlays sync --
|
|
171
|
+
dotagents overlays sync --prune # also clear what .gitignore/.ignore protect: exactly upstream
|
|
167
172
|
dotagents overlays remove python # delete the overlay dir, unpublish its skills, un-merge its rules
|
|
168
173
|
dotagents overlays show python # describe one: manifest, requires, setup, skills, source (--json)
|
|
169
174
|
```
|
|
@@ -184,13 +189,17 @@ dotagents overlays show python # describe one: manifest, requires, s
|
|
|
184
189
|
it as done.
|
|
185
190
|
- **`sync`** refreshes each installed overlay from the repo it was installed from
|
|
186
191
|
(recorded in `<overlay>/.dotagents-install.json`); `--repo` replaces that recorded
|
|
187
|
-
source for the run.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
`--
|
|
192
|
+
source for the run. The install is made to match the source exactly: new and changed
|
|
193
|
+
files land, `overlay.toml` is refreshed, and files the source does not ship are
|
|
194
|
+
removed. A file you edited (or added) there is copied to
|
|
195
|
+
`<store>/install_backup/<timestamp>/overlays/<name>/` before it is replaced or
|
|
196
|
+
removed. What the `.gitignore` / `.ignore` at the overlay's root match — setup
|
|
197
|
+
output, local state — and tool caches (`__pycache__`, `.venv`, …) are the install's own and
|
|
198
|
+
left alone; `--prune` clears them too, leaving exactly the upstream files. A
|
|
199
|
+
`requires` added upstream is installed, and published skill copies are refreshed.
|
|
200
|
+
`add` of an overlay already installed does the same (with `--prune` too). Keep your
|
|
201
|
+
own additions outside `<store>/overlays/` — a `kb/` file of your own, an
|
|
202
|
+
`AGENTS.local.md` — where a sync never touches them.
|
|
194
203
|
- **`remove`** deletes the overlay's directory, unpublishes the skills it published
|
|
195
204
|
(and their links in Claude's skills dir), and recomposes `AGENTS.md`'s managed block over the overlays that remain, so its
|
|
196
205
|
rules and routing leave with it. It refuses an overlay another installed overlay
|
|
@@ -272,6 +281,11 @@ dotagents env --diff --format json # only vars that differ from the caller's e
|
|
|
272
281
|
environment, the working directory, the stores, the overlays, every env and `lib`
|
|
273
282
|
file), for at most five minutes; the per-command env loaders use it. The cache is
|
|
274
283
|
owner-only, under `<user store>/.cache/env/`.
|
|
284
|
+
- `--into <file>` — write into `<file>` instead of stdout, as the one block this
|
|
285
|
+
command owns there (between `: dotagents-env-begin` / `: dotagents-env-end`):
|
|
286
|
+
an earlier block is replaced, anything else in the file is kept. The SessionStart
|
|
287
|
+
hook writes `$CLAUDE_ENV_FILE` this way, so the file stays one block however often
|
|
288
|
+
the hook runs. `export` format only.
|
|
275
289
|
- `-g` / `--global` — skip the project-level env files (the store is unaffected).
|
|
276
290
|
- `--agents-dir <dir>` — user store override for this run.
|
|
277
291
|
|
|
@@ -307,7 +321,12 @@ form and drop names that are not shell identifiers.
|
|
|
307
321
|
overlay, where `NAME` is the overlay's name upper-cased with `-` turned into `_`
|
|
308
322
|
(`my-ov` → `MY_OV_OVERLAY_ROOT`). That is the same name `context` expands as a
|
|
309
323
|
`<NAME_OVERLAY_ROOT>` placeholder, so an env file and a context file refer to an
|
|
310
|
-
overlay's install dir by one name.
|
|
324
|
+
overlay's install dir by one name. When `dotagents` runs from a `.pyz`,
|
|
325
|
+
`AGENTS_PYLIB` names that archive: the libraries it bundles (duho,
|
|
326
|
+
pathlib_next) import from it, so an overlay built on them appends it to
|
|
327
|
+
`sys.path` when its own import fails. An installed `dotagents` sets nothing,
|
|
328
|
+
since those libraries are already in `AGENTS_PYTHON`'s site-packages. It is
|
|
329
|
+
never put on `PYTHONPATH`, where it would shadow a project's own copy.
|
|
311
330
|
3. **`PATH`** — every level's `bin/` (each store's overlays, then the store) goes
|
|
312
331
|
to the front in that order, including ones that do not exist yet, so an `env.py`
|
|
313
332
|
and every subprocess can call an overlay's helpers by name. The order holds even
|
|
@@ -96,7 +96,7 @@ python -m dotagents build-pyz --out dist/dotagents.pyz # or build it (needs a
|
|
|
96
96
|
holds the git checkouts and remote sources the repos materialize (the directory carries a
|
|
97
97
|
`.gitignore` of `*`, so a store kept in git never records them).
|
|
98
98
|
- `install_backup/<timestamp>/` — what `init --force` replaced, and what
|
|
99
|
-
`overlays
|
|
99
|
+
`overlays add` / `sync` replaced or removed that had been edited in an installed overlay.
|
|
100
100
|
- `dotagents/cmds/` — only if you create it: your own command modules (see
|
|
101
101
|
[Authoring → Custom commands](authoring.md#custom-commands)).
|
|
102
102
|
- `dotagents/config.toml` — only after `init --from`: records that base, so a later
|
|
@@ -73,10 +73,14 @@ store). Each overlay:
|
|
|
73
73
|
reads that dir sees the same skills.
|
|
74
74
|
|
|
75
75
|
`sync` refreshes each overlay from the repo it was installed from (`--repo` replaces
|
|
76
|
-
that source for the run)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
that source for the run) and makes the install exactly the source: changed files are
|
|
77
|
+
replaced and files the source does not ship are removed, anything edited there backed
|
|
78
|
+
up under `<store>/install_backup/` first. What the `.gitignore` / `.ignore` at the
|
|
79
|
+
overlay's root match (an ignore file in a subdirectory is just a file it ships), and
|
|
80
|
+
tool caches, belong to the install (a setup script's output, local
|
|
81
|
+
state) and are left alone; `--prune` clears them too. A `requires` added upstream is
|
|
82
|
+
installed. An installed overlay is upstream's copy, not a place for your edits: keep
|
|
83
|
+
those in your own files (a `kb/` file, `AGENTS.local.md`).
|
|
80
84
|
|
|
81
85
|
Removing an overlay deletes only its directory and unpublishes only the skills **it**
|
|
82
86
|
published (a copy the user edited is left alone). Its lines in `AGENTS.md`'s managed
|
|
@@ -23,7 +23,8 @@ carry the opinions.
|
|
|
23
23
|
composable **overlays** you layer in explicitly with `dotagents overlays add
|
|
24
24
|
<name>`. The overlays in this repo are examples — payloads riding on dotagents,
|
|
25
25
|
swappable for your own; see [Overlays](guide/overlays.md) for what each ships.
|
|
26
|
-
|
|
26
|
+
An installed overlay is kept exactly as upstream ships it (what the `.gitignore` /
|
|
27
|
+
`.ignore` at its root protect stays yours), so your own changes live in your own files.
|
|
27
28
|
- **Two scopes.** Config installs into a **user** store (`~/.agents`, configurable)
|
|
28
29
|
or a **project** store (`<project>/.agents`). Overlays, skills, commands, and env
|
|
29
30
|
files all resolve across the same scope precedence.
|
|
@@ -31,14 +31,14 @@ and an error saying a command is required, and exits 2.
|
|
|
31
31
|
| Command | Contract |
|
|
32
32
|
| --- | --- |
|
|
33
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] [--dry-run]` | Install each overlay and its `requires` into `<store>/overlays/<name
|
|
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; a fresh install whose setup fails is rolled back. No name: exit 2. |
|
|
35
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] [--
|
|
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`. Exits 1 when an overlay's repo cannot be loaded, its source lies inside `<store>/overlays/`, or its setup fails. |
|
|
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. |
|
|
40
40
|
| `path [-g] [--lib] [--format list\|native\|posix\|json]` | Print the bin dirs `env` puts on `PATH` (`--lib`: the existing lib dirs it puts on `PYTHONPATH`), highest precedence first; runs no env file. `posix` is `:`-joined, MSYS2 form on Windows. |
|
|
41
|
-
| `env [-g] [--format F] [--diff] [--cache]` | Print the assembled environment (`--diff`: only what differs from the caller's; `--cache`: replay the previous output while `env_cache_key` holds, up to `ENV_CACHE_TTL
|
|
41
|
+
| `env [-g] [--format F] [--diff] [--cache] [--into FILE]` | Print the assembled environment (`--diff`: only what differs from the caller's; `--cache`: replay the previous output while `env_cache_key` holds, up to `ENV_CACHE_TTL`; `--into FILE`: write it into FILE as the one block this command owns there) in format `F`: `auto` (default: the calling shell), `export`/`posix`/`sh`/`bash`, `dotenv`/`env`, `powershell`/`pwsh`/`ps`, `cmd`/`bat`/`batch`, `fish`, `json`, `ini`, `yaml`. |
|
|
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. |
|
|
44
44
|
| `about [--json]` | `dotagents-cli <version>`, then `<distribution> <version>` per bundled (`.pyz`) or installed package. |
|
|
@@ -68,6 +68,10 @@ are skipped.
|
|
|
68
68
|
- `class Dotagents(LoggingArgs, Cli)` — the umbrella; field `cmdspath: list[str]`.
|
|
69
69
|
- `CMDS_PATH_ENV = "AGENTS_CMDS_PATH"`.
|
|
70
70
|
- Re-exported for command modules: `DotAgentsArgs`, `_write_stdout` (see below).
|
|
71
|
+
- `kebab_name(class_name) -> str` — a discovered command's default name when its
|
|
72
|
+
class declares no `_parsername_`: `LeakCheck` -> `leak-check`, `HTTPServer` ->
|
|
73
|
+
`http-server`, `my_cmd` -> `my-cmd`. `_parsername_` is optional in a command
|
|
74
|
+
module; an explicit one always wins.
|
|
71
75
|
|
|
72
76
|
## `dotagents.cli._common`
|
|
73
77
|
|
|
@@ -75,7 +79,8 @@ are skipped.
|
|
|
75
79
|
`global_scope: bool = False` (`--global`, `-g`) and
|
|
76
80
|
`agents_dir: Optional[Path] = None` (`--agents-dir`); `resolve_scope(*,
|
|
77
81
|
project_root=None) -> Scope` (via `_scope.resolve_scope`). Subclass it alone
|
|
78
|
-
(`class X(DotAgentsArgs)`), define `
|
|
82
|
+
(`class X(DotAgentsArgs)`), define `__call__(self) -> int` and optionally
|
|
83
|
+
`_parsername_` (default: `kebab_name` of the class, for a discovered module). A
|
|
79
84
|
subclass may redeclare a field with the same type and default to change its help.
|
|
80
85
|
- `_write_stdout(text) -> None` — write to stdout as UTF-8 whatever the console's
|
|
81
86
|
encoding (a bare `print` fails on a non-Latin-1 character under cp1252).
|
|
@@ -95,6 +100,23 @@ are skipped.
|
|
|
95
100
|
`OVERLAY_ROOT_NOTE` (`dotagents._overlays`), `resolve_user_store`
|
|
96
101
|
(`dotagents._scope`).
|
|
97
102
|
|
|
103
|
+
## `dotagents._ignore`
|
|
104
|
+
|
|
105
|
+
The `.gitignore` / `.ignore` at the ROOT of a directory, read as git reads a
|
|
106
|
+
`.gitignore` (pure stdlib) -- what an installed overlay keeps as its own when `add`
|
|
107
|
+
/ `sync` mirror its source. An ignore file in a subdirectory is an ordinary file;
|
|
108
|
+
nothing above the root is read.
|
|
109
|
+
|
|
110
|
+
- `IGNORE_FILES = (".gitignore", ".ignore")` — read at the root in that order, so
|
|
111
|
+
`.ignore` wins (ripgrep's precedence).
|
|
112
|
+
- `parse(text, base="") -> list` — one file's rules (`base`: its directory):
|
|
113
|
+
comments, `\#` / `\!` escapes, `!` negation, leading/middle `/` anchoring,
|
|
114
|
+
trailing `/` directory-only, `*`, `?`, `[...]`, `**`.
|
|
115
|
+
- `class IgnoreRules(rules=())` — `for_root(root)` reads `root`'s two files;
|
|
116
|
+
`ignored(rel, is_dir=False) -> bool` decides a `/`-joined path (a pattern without
|
|
117
|
+
a slash matches at any depth), a path under an ignored directory staying ignored
|
|
118
|
+
whatever a later `!` says, as in git.
|
|
119
|
+
|
|
98
120
|
## `dotagents._resources`
|
|
99
121
|
|
|
100
122
|
The package's own data; library code, importing nothing from `dotagents.cli`.
|
|
@@ -108,6 +130,10 @@ The package's own data; library code, importing nothing from `dotagents.cli`.
|
|
|
108
130
|
store at `dest`: the project template for a project store when the base has one,
|
|
109
131
|
else the user template, else `<src>/AGENTS.md`; `{{AGENTS_MD}}` rendered as the
|
|
110
132
|
absolute POSIX path of `<dest>/AGENTS.md`.
|
|
133
|
+
- `pyz_archive() -> str | None` — the `.pyz` this dotagents is imported from (the
|
|
134
|
+
ancestor of the module's `__file__` that is a file), or `None` for a plain
|
|
135
|
+
install. The archive also holds the vendored duho and pathlib_next; `env`
|
|
136
|
+
exports it as `AGENTS_PYLIB`.
|
|
111
137
|
|
|
112
138
|
## Commands — `dotagents.cli.init`, `dotagents.cli.overlays`, `dotagents.cli.context`, `dotagents.cli.env`, `dotagents.cli.path`, `dotagents.cli.about`, `dotagents.cli.build_pyz`
|
|
113
139
|
|
|
@@ -119,6 +145,13 @@ returns the exit code.
|
|
|
119
145
|
("markdown", "system-reminder", "json")`); `env.Env`; `path.PathCmd`
|
|
120
146
|
(`PATH_FORMATS = ("list", "native", "posix", "json")`); `build_pyz.BuildPyz`;
|
|
121
147
|
`about.About`.
|
|
148
|
+
- `env`: `write_into(path, text, output_format)` — what `--into` does: the file
|
|
149
|
+
keeps ONE block between `INTO_BEGIN = ": dotagents-env-begin"` and
|
|
150
|
+
`INTO_END = ": dotagents-env-end"` (no-op commands, not comments, so a `; cmd`
|
|
151
|
+
appended to the last line still runs; earlier blocks removed, other lines kept,
|
|
152
|
+
the new block last), written atomically; `INTO_FORMATS = ("export",)`. With
|
|
153
|
+
`--diff --format export`, a `PATH` that is the caller's with entries in front is
|
|
154
|
+
written as `export PATH='<prefix>'"${PATH:+:$PATH}"`.
|
|
122
155
|
- `about`: `DISTRIBUTION = "dotagents-cli"`, `BUNDLE_FILE = "_bundle.json"` (written
|
|
123
156
|
by `build-pyz` into the package), `RUNTIME_PACKAGES = ("duho", "pathlib_next",
|
|
124
157
|
"uritools", "netimps", "requests")` (the only packages a plain install reports);
|
|
@@ -187,9 +220,9 @@ returns the exit code.
|
|
|
187
220
|
string arrays including multi-line strings, an integer); `None` plus one warning
|
|
188
221
|
when it is not valid TOML.
|
|
189
222
|
- `class InstallResult` — what `install_to` did: `written`, `unchanged`,
|
|
190
|
-
`
|
|
191
|
-
|
|
192
|
-
|
|
223
|
+
`replaced` (edited here, replaced by the source's file), `removed` (not in the
|
|
224
|
+
source, or cleared by `prune`), `backed_up`, `lines`; property `skipped`
|
|
225
|
+
(= unchanged). Unpacks as `(written, skipped, lines)`.
|
|
193
226
|
- `class Overlay(path, store=None)` — one overlay directory; `os.PathLike`; equal
|
|
194
227
|
and hashed by `path`; nothing read at construction.
|
|
195
228
|
- Class data: `NAME_RE`, `RESERVED_NAMES` (Windows device names),
|
|
@@ -235,12 +268,16 @@ returns the exit code.
|
|
|
235
268
|
- `rule_blocks(rel_paths) -> tuple[list[str], list[str]]` — `(blocks, warnings)`:
|
|
236
269
|
each file's leading `- **` bullets up to its next `## ` heading; a path outside
|
|
237
270
|
the overlay, missing or unreadable is a warning.
|
|
238
|
-
- `
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
271
|
+
- `ignore_rules() -> IgnoreRules` — the rules of the `.gitignore` / `.ignore`
|
|
272
|
+
at the overlay's root (`dotagents._ignore`).
|
|
273
|
+
- `install_to(dest_overlay_dir, dry_run, *, prune=False, backup_root=None,
|
|
274
|
+
source=None) -> InstallResult` — make the install exactly the overlay:
|
|
275
|
+
`files()` installed or replaced, `overlay.toml` refreshed, every other file
|
|
276
|
+
removed; what `ignore_rules()` matches, the install record and `SKIP_PARTS`
|
|
277
|
+
caches are never copied, replaced or removed unless `prune` (which clears
|
|
278
|
+
them, without backup); a replaced or removed file that is not what dotagents
|
|
279
|
+
installed is copied under `backup_root` first; writes the install record
|
|
280
|
+
(`source`, or the previous one when `None`).
|
|
244
281
|
- `OVERLAY_ROOT_NOTE: str` — the line emitted once above overlay routing lines that
|
|
245
282
|
use `$<NAME>_OVERLAY_ROOT`.
|
|
246
283
|
- `recompose_overlay_block(agents_md, base_block, overlays, dry_run, logger) -> bool`
|
|
@@ -322,7 +359,11 @@ proxy model.
|
|
|
322
359
|
user-scope walk `AGENTS_PROJECT_ROOT` is set only when unset. Only when unset:
|
|
323
360
|
`AGENTS_PYTHON` (`sys.executable`) and one `<NAME>_OVERLAY_ROOT` per
|
|
324
361
|
`scope.overlays` (a value pinned to the user store's copy is re-pointed when a
|
|
325
|
-
project copy shadows it).
|
|
362
|
+
project copy shadows it). `AGENTS_PYLIB` (`_env.PYLIB_VAR`): the `.pyz` when
|
|
363
|
+
dotagents runs from one (`_resources.pyz_archive()`), else not set — where its
|
|
364
|
+
own libraries (duho, pathlib_next) import from by zipimport for an overlay
|
|
365
|
+
built on them. Never added to `PYTHONPATH`: a consumer appends it to
|
|
366
|
+
`sys.path` when its import fails.
|
|
326
367
|
- `PATH`: every level's `bin` (contract A, not project-root, missing dirs included)
|
|
327
368
|
at the front in that order, whatever the caller's `PATH` held; empty and
|
|
328
369
|
cwd-relative inherited entries are dropped.
|
|
@@ -631,6 +672,8 @@ Read:
|
|
|
631
672
|
- `AGENTS_HARNESS` — the running harness (registry name or harness id), for
|
|
632
673
|
identity. `AGENTS_PYTHON` — the interpreter for `env.py`. `AGENTS_PYTHONPATH` —
|
|
633
674
|
the overlay/store `lib` dirs `env` put on `PYTHONPATH`, highest precedence first.
|
|
675
|
+
`AGENTS_PYLIB` — the `.pyz` dotagents runs from (duho and pathlib_next import
|
|
676
|
+
from it), unset for an installed dotagents.
|
|
634
677
|
- Harness config dirs: `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, `PI_CODING_AGENT_DIR`.
|
|
635
678
|
Harness markers: `CLAUDECODE`, `CLAUDE_CODE_ENTRYPOINT`, `GEMINI_CLI`,
|
|
636
679
|
`CODEX_SANDBOX*`, `CURSOR_AGENT`, `PI_CODING_AGENT`. Model vars: `ANTHROPIC_MODEL`,
|
|
@@ -644,7 +687,7 @@ Read:
|
|
|
644
687
|
|
|
645
688
|
Emitted by `env` (and applied by `launch`): `AGENTS_HARNESS`, `AGENTS_VENDOR`,
|
|
646
689
|
`AGENT`, `AGENTS_MODEL`, `AGENTS_HOME`, `AGENTS_PROJECT_ROOT`, `AGENTS_PYTHON`,
|
|
647
|
-
`<NAME>_OVERLAY_ROOT`, `PATH`, `AGENTS_PYTHONPATH`, `AGENTS_PROXY` and the mirrored
|
|
690
|
+
`AGENTS_PYLIB` (from a `.pyz` only), `<NAME>_OVERLAY_ROOT`, `PATH`, `AGENTS_PYTHONPATH`, `AGENTS_PROXY` and the mirrored
|
|
648
691
|
proxy vars, plus whatever the env files set. `AGENTS_AGENT` is never emitted.
|
|
649
692
|
`launch` also exports `AGENTS_CONTEXT_FILE`.
|
|
650
693
|
|
|
@@ -500,14 +500,21 @@ class ClaudeAgent(Agent):
|
|
|
500
500
|
# SessionStart does two things, in one `type: command` hook (SessionStart
|
|
501
501
|
# supports only command/mcp_tool hooks, and env must run before context):
|
|
502
502
|
#
|
|
503
|
-
# 1. `dotagents env --diff` output
|
|
503
|
+
# 1. `dotagents env --diff` output goes into $CLAUDE_ENV_FILE
|
|
504
504
|
# (code.claude.com/docs/en/env-vars + hooks.md "Persist environment
|
|
505
505
|
# variables"): Claude sources that file before each Bash command. It is
|
|
506
506
|
# set only inside SessionStart/Setup/CwdChanged/FileChanged hook
|
|
507
507
|
# processes, never in the session's own environment.
|
|
508
|
-
# *
|
|
508
|
+
# * `--into`, not `>>`: the block a previous run wrote is REPLACED
|
|
509
|
+
# and anything else in the file (another hook's lines) is kept.
|
|
510
|
+
# SessionStart re-runs on resume, compact and clear; appending
|
|
511
|
+
# grew the file by the whole env each time, and Claude Code inlines
|
|
512
|
+
# it into every Bash command's `bash -c` argument, which Git for
|
|
513
|
+
# Windows' bash truncates at about 8 KB -- every Bash call then
|
|
514
|
+
# failed with an unterminated quote. PATH is written relative to
|
|
515
|
+
# the shell's own ($PATH), which keeps the block small.
|
|
509
516
|
# * Guard on non-empty (`[ -n "$CLAUDE_ENV_FILE" ]`) -- when unset,
|
|
510
|
-
#
|
|
517
|
+
# `--into ""` has nowhere to write.
|
|
511
518
|
#
|
|
512
519
|
# 2. `dotagents context`: Claude injects a SessionStart hook's stdout into
|
|
513
520
|
# the session context.
|
|
@@ -534,7 +541,7 @@ class ClaudeAgent(Agent):
|
|
|
534
541
|
SESSION_START_COMMAND = (
|
|
535
542
|
_HOOK_DOTAGENTS
|
|
536
543
|
+ 'if [ -n "$CLAUDE_ENV_FILE" ]; then '
|
|
537
|
-
'"$d" env --diff --format export
|
|
544
|
+
'"$d" env --diff --format export --into "$CLAUDE_ENV_FILE"; '
|
|
538
545
|
"fi; "
|
|
539
546
|
'"$d" context'
|
|
540
547
|
)
|
|
@@ -546,10 +553,22 @@ class ClaudeAgent(Agent):
|
|
|
546
553
|
# `%q` quotes the path for the bash that sources the file: a `'` in a
|
|
547
554
|
# directory name used to leave an unterminated quote that broke every
|
|
548
555
|
# later source of $CLAUDE_ENV_FILE (and a crafted name ran commands).
|
|
556
|
+
# The file keeps ONE pin, the latest: an earlier `export
|
|
557
|
+
# AGENTS_PROJECT_ROOT=` line is dropped and every other line (another
|
|
558
|
+
# hook's) kept. Appending grew the file by a line per `cd`, and Claude Code
|
|
559
|
+
# inlines it into every Bash command (see SESSION_START_COMMAND). Pure bash,
|
|
560
|
+
# 3.2-compatible (macOS): no mapfile, no external command, so a `cd` stays
|
|
561
|
+
# instant.
|
|
549
562
|
CWD_CHANGED_COMMAND = (
|
|
550
563
|
'if [ -n "$CLAUDE_ENV_FILE" ] && [ -d .agents ]; then '
|
|
551
|
-
"
|
|
552
|
-
'
|
|
564
|
+
"kept=(); "
|
|
565
|
+
'if [ -f "$CLAUDE_ENV_FILE" ]; then '
|
|
566
|
+
'while IFS= read -r line || [ -n "$line" ]; do '
|
|
567
|
+
'case "$line" in "export AGENTS_PROJECT_ROOT="*) ;; *) kept+=("$line") ;; esac; '
|
|
568
|
+
'done < "$CLAUDE_ENV_FILE"; fi; '
|
|
569
|
+
'{ for line in ${kept[@]+"${kept[@]}"}; do printf \'%s\\n\' "$line"; done; '
|
|
570
|
+
"printf 'export AGENTS_PROJECT_ROOT=%q\\n' \"$(pwd -W 2>/dev/null || pwd)\"; "
|
|
571
|
+
'} > "$CLAUDE_ENV_FILE"; fi; '
|
|
553
572
|
"[ -f AGENTS.md ] && cat AGENTS.md || true"
|
|
554
573
|
)
|
|
555
574
|
|
|
@@ -59,7 +59,10 @@ The identity/proxy model is wired into the output around the file chain:
|
|
|
59
59
|
the same set :func:`get_overlay_roots` lists, named by
|
|
60
60
|
:attr:`_overlays.Overlay.root_var` --
|
|
61
61
|
the same name ``dotagents context`` expands as a placeholder), so an env
|
|
62
|
-
file can reference an overlay's install dir by name.
|
|
62
|
+
file can reference an overlay's install dir by name. ``AGENTS_PYLIB``
|
|
63
|
+
(:data:`PYLIB_VAR`) names the ``.pyz`` when dotagents runs from one --
|
|
64
|
+
where its own libraries (duho, pathlib_next) import from for an overlay
|
|
65
|
+
built on them; never put on ``PYTHONPATH``.
|
|
63
66
|
* **Proxy** is normalized AFTER the file chain: ``AGENTS_PROXY`` is seeded if
|
|
64
67
|
unset (from ``AGENTS_WEBFETCH_PROXY_URL`` else the global
|
|
65
68
|
HTTPS/HTTP/ALL_PROXY, either case); any proxy var that *already exists* is
|
|
@@ -94,6 +97,11 @@ from typing import Iterable, Optional
|
|
|
94
97
|
|
|
95
98
|
from dotagents._scope import Scope, project_root_default
|
|
96
99
|
|
|
100
|
+
#: Names the ``.pyz`` dotagents runs from (unset for an installed dotagents,
|
|
101
|
+
#: whose libraries are in ``AGENTS_PYTHON``'s site-packages): an overlay built
|
|
102
|
+
#: on duho appends it to ``sys.path`` when ``import duho`` fails.
|
|
103
|
+
PYLIB_VAR = "AGENTS_PYLIB"
|
|
104
|
+
|
|
97
105
|
|
|
98
106
|
class EnvChanges(dict):
|
|
99
107
|
"""A change set: the vars set (``dict[str, str]``, as before) plus
|
|
@@ -1047,6 +1055,17 @@ def get_environment(
|
|
|
1047
1055
|
# `sys.executable` is '' or None under an embedding host: then nothing is
|
|
1048
1056
|
# exported rather than an empty command name.
|
|
1049
1057
|
_seed("AGENTS_PYTHON", sys.executable)
|
|
1058
|
+
# --- AGENTS_PYLIB --- where dotagents' own libraries (duho, pathlib_next)
|
|
1059
|
+
# import from for an overlay that builds on them. Set only when dotagents
|
|
1060
|
+
# runs from a .pyz: the archive, importable by zipimport. An installed
|
|
1061
|
+
# dotagents has them in AGENTS_PYTHON's site-packages already. Never put on
|
|
1062
|
+
# PYTHONPATH, which would shadow a project's own copy: a consumer appends
|
|
1063
|
+
# it to sys.path when its import fails.
|
|
1064
|
+
from dotagents._resources import pyz_archive
|
|
1065
|
+
|
|
1066
|
+
pylib = pyz_archive()
|
|
1067
|
+
if pylib and osenv.get(PYLIB_VAR) != pylib:
|
|
1068
|
+
_apply({PYLIB_VAR: pylib})
|
|
1050
1069
|
|
|
1051
1070
|
# --- Overlay roots --- one `<NAME>_OVERLAY_ROOT` per installed overlay, the
|
|
1052
1071
|
# same name `dotagents context` expands as a `<NAME_OVERLAY_ROOT>` placeholder
|
|
@@ -1208,10 +1227,11 @@ def env_cache_key(scope: Scope, base_env: "dict[str, str]", *parts: str) -> str:
|
|
|
1208
1227
|
import hashlib
|
|
1209
1228
|
|
|
1210
1229
|
from dotagents import __version__
|
|
1230
|
+
from dotagents._resources import pyz_archive
|
|
1211
1231
|
|
|
1212
1232
|
scope = _absolute_scope(scope)
|
|
1213
1233
|
items = [
|
|
1214
|
-
__version__, sys.executable or "", os.getcwd(), scope.level,
|
|
1234
|
+
__version__, sys.executable or "", pyz_archive() or "", os.getcwd(), scope.level,
|
|
1215
1235
|
str(scope.user_root), str(scope.agents_root), str(scope.project_root),
|
|
1216
1236
|
str(scope.system_root), *parts,
|
|
1217
1237
|
]
|