dotagents-cli 0.8.3__tar.gz → 0.9.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/CHANGELOG.md +172 -1
  2. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/PKG-INFO +42 -27
  3. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/README.md +41 -26
  4. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/guide/authoring.md +119 -39
  5. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/guide/commands.md +62 -48
  6. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/guide/install.md +11 -6
  7. dotagents_cli-0.9.1/docs/guide/overlays.md +520 -0
  8. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/pyproject.toml +1 -1
  9. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/AGENTS.md +409 -145
  10. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/__init__.py +1 -1
  11. dotagents_cli-0.9.1/src/dotagents/_activate.py +231 -0
  12. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_agents.py +10 -8
  13. dotagents_cli-0.9.1/src/dotagents/_aos.py +2492 -0
  14. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_context.py +39 -27
  15. dotagents_cli-0.9.1/src/dotagents/_deps.py +393 -0
  16. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_env.py +417 -134
  17. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_launchers.py +6 -5
  18. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_mcp_gateway_clients.py +24 -7
  19. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_mcp_gateway_config.py +71 -24
  20. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_overlay/dotagents/templates/AGENTS.md +2 -2
  21. dotagents_cli-0.9.1/src/dotagents/_overlays.py +990 -0
  22. dotagents_cli-0.9.1/src/dotagents/_policy.py +189 -0
  23. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_pyvenv.py +97 -63
  24. dotagents_cli-0.9.1/src/dotagents/_run.py +228 -0
  25. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_scope.py +14 -5
  26. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_skills.py +26 -6
  27. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_sources.py +90 -10
  28. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/__init__.py +11 -5
  29. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/init.py +3 -2
  30. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/overlays.py +473 -125
  31. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/path.py +5 -3
  32. dotagents_cli-0.9.1/tests/aos_vectors/README.md +31 -0
  33. dotagents_cli-0.9.1/tests/aos_vectors/REVISION +1 -0
  34. dotagents_cli-0.9.1/tests/aos_vectors/compose.json +1998 -0
  35. dotagents_cli-0.9.1/tests/aos_vectors/digest.json +641 -0
  36. dotagents_cli-0.9.1/tests/aos_vectors/effective.json +5210 -0
  37. dotagents_cli-0.9.1/tests/aos_vectors/names.json +192 -0
  38. dotagents_cli-0.9.1/tests/aos_vectors/reading.json +2019 -0
  39. dotagents_cli-0.9.1/tests/aos_vectors/source.json +269 -0
  40. dotagents_cli-0.9.1/tests/aos_vectors/validation.json +2052 -0
  41. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/conftest.py +5 -4
  42. dotagents_cli-0.9.1/tests/test_aos_consumer.py +526 -0
  43. dotagents_cli-0.9.1/tests/test_aos_vectors.py +333 -0
  44. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_audit_leak.py +1 -1
  45. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_cli_main.py +4 -4
  46. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_cmds_discovery.py +1 -1
  47. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_context.py +24 -7
  48. dotagents_cli-0.9.1/tests/test_deps.py +212 -0
  49. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_env.py +82 -14
  50. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_env_regressions.py +1 -1
  51. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_env_safety.py +7 -6
  52. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_fix_env.py +3 -0
  53. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_fix_overlays.py +57 -58
  54. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_fix_scope_context.py +9 -4
  55. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_fix_skills_adapters.py +11 -3
  56. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_git_ssl_revoke.py +4 -1
  57. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_init_base.py +1 -1
  58. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_launchers.py +37 -30
  59. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_local_additions.py +18 -2
  60. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_mcp.py +13 -8
  61. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_no_internal_labels.py +5 -0
  62. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_overlay_libs.py +20 -11
  63. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_overlays_cli.py +42 -22
  64. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_overlays_command.py +199 -38
  65. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_path_timeout_frontmatter.py +41 -19
  66. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_powershell_env_hook.py +29 -8
  67. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_pyvenv_core.py +27 -21
  68. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_sources.py +13 -13
  69. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_sources_uri.py +4 -4
  70. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tools/audit.py +21 -15
  71. dotagents_cli-0.8.3/docs/guide/overlays.md +0 -343
  72. dotagents_cli-0.8.3/src/dotagents/_ignore.py +0 -146
  73. dotagents_cli-0.8.3/src/dotagents/_overlays.py +0 -1227
  74. dotagents_cli-0.8.3/tests/test_ignore.py +0 -58
  75. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/.gitignore +0 -0
  76. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/LICENSE +0 -0
  77. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/agents.md +0 -0
  78. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/cli.md +0 -0
  79. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/commands.md +0 -0
  80. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/context.md +0 -0
  81. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/env.md +0 -0
  82. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/fs.md +0 -0
  83. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/hooks.md +0 -0
  84. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/merge.md +0 -0
  85. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/overlays.md +0 -0
  86. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/reference.md +0 -0
  87. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/resources.md +0 -0
  88. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/scope.md +0 -0
  89. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/skills.md +0 -0
  90. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/sources.md +0 -0
  91. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/api/wrappers.md +0 -0
  92. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/changelog.md +0 -0
  93. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/guide/private-sync.md +0 -0
  94. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/docs/index.md +0 -0
  95. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/install.py +0 -0
  96. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/mkdocs.yml +0 -0
  97. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/__main__.py +0 -0
  98. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_fs.py +0 -0
  99. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_hooks.py +0 -0
  100. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_mcp_gateway.py +0 -0
  101. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_merge.py +0 -0
  102. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_overlay/dotagents/cmds/findings.py +0 -0
  103. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_overlay/dotagents/cmds/launch.py +0 -0
  104. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_overlay/dotagents/hooks/preinvocation_antigravity_context.py +0 -0
  105. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_overlay/dotagents/hooks/pretooluse_codex_env.py +0 -0
  106. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_overlay/dotagents/hooks/sessionstart_codex_context.py +0 -0
  107. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_overlay/dotagents/templates/PROJECT.md +0 -0
  108. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_pipwheel.py +0 -0
  109. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_resources.py +0 -0
  110. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/_wrappers.py +0 -0
  111. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/_common.py +0 -0
  112. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/about.py +0 -0
  113. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/build_pyz.py +0 -0
  114. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/context.py +0 -0
  115. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/env.py +0 -0
  116. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/cli/mcp.py +0 -0
  117. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/src/dotagents/py.typed +0 -0
  118. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/_helpers.py +0 -0
  119. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/_shell.py +0 -0
  120. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_about.py +0 -0
  121. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_agents.py +0 -0
  122. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_api_header.py +0 -0
  123. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_build_pyz.py +0 -0
  124. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_cloud_setup.py +0 -0
  125. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_env_cli_scope.py +0 -0
  126. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_env_format.py +0 -0
  127. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_env_into.py +0 -0
  128. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_findings_cmd.py +0 -0
  129. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_fix_adapters.py +0 -0
  130. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_fix_cli.py +0 -0
  131. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_fix_hooks.py +0 -0
  132. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_fix_init.py +0 -0
  133. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_fix_packaging.py +0 -0
  134. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_hooks.py +0 -0
  135. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_last_mile.py +0 -0
  136. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_launch_cmd.py +0 -0
  137. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_pipwheel.py +0 -0
  138. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_quoting_injection_safety.py +0 -0
  139. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_scope.py +0 -0
  140. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_wire_hooks.py +0 -0
  141. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tests/test_wrappers.py +0 -0
  142. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tools/cloud-setup.sh +0 -0
  143. {dotagents_cli-0.8.3 → dotagents_cli-0.9.1}/tools/pyz_smoke.sh +0 -0
@@ -7,6 +7,175 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.1] - 2026-11-06
11
+
12
+ ### Fixed
13
+
14
+ - The Claude Code PowerShell-tool env loader (`init --powershell-env-hook`) no longer
15
+ answers `permissionDecision: "allow"`, which ran calls that would have asked and, under
16
+ `--permission-mode dontAsk` or with no way to ask, calls that would have been refused.
17
+ It now only rewrites the call and the permission system decides. A PowerShell call
18
+ therefore asks unless `PowerShell` itself is allowed, since rules judge the rewritten
19
+ command. An `init --powershell-env-hook` replaces a loader already wired.
20
+
21
+ ## [0.9.0] - 2026-11-04
22
+
23
+ dotagents implements the [Agent Overlay Specification](https://boriken-dev.github.io/agent-overlay-spec/)
24
+ (AOS, edition `0.1.0-draft`) and passes its conformance vectors.
25
+
26
+ ### Changed (breaking)
27
+
28
+ - An overlay's manifest is `overlay.cfg` (TOML by default; `#!json` or `#!yaml` on
29
+ its first line for JSON or YAML, the latter with the `yaml` extra). `overlay.toml`
30
+ is not read any more; an overlay that still has one gets a warning naming it.
31
+ - A manifest that does not validate against AOS is ignored whole, with a warning
32
+ naming where it is wrong, and `overlays add` / `sync` refuse it. It used to keep
33
+ its valid fields and drop the others. The small built-in TOML reader is gone: below
34
+ Python 3.11 manifests need `tomli` (a declared dependency, vendored in the `.pyz`).
35
+ - An overlay's Python modules go in `lib/python/`, prepended to `PYTHONPATH`; a
36
+ bare `lib/` is not on any path any more. `bin/` and `lib/python/` count only when
37
+ they hold a file.
38
+ - A `bin/<name>.py` no longer gets a launcher by its name: a command is a
39
+ `[scripts]` entry (`curl = "bin/curl.py"`). `bin/` itself stays on `PATH`.
40
+ - An overlay's setup is the first `[[setup]]` variant it declares for the OS, else
41
+ one `setup.<ext>` at its root -- the first, in the order `.py`, `.js`, `.mjs`,
42
+ `.cjs`, then `.ps1` on Windows, then `.bash`, `.sh` elsewhere, that this machine
43
+ can run -- taken to need the network. It is told its phase as its first argument
44
+ and `AOS_SETUP_PHASE`: `install` on the first `add`, `sync` on every `add` or
45
+ `sync` after one succeeded, and `remove` when `overlays remove` deletes the
46
+ overlay (new: setup used to run with no argument, and never on removal). A script
47
+ must treat a phase it does not know as success. It runs after the overlay's
48
+ dependencies are installed, in the overlay's own environment, with
49
+ `AOS_OVERLAY_ROOT`, `AOS_OVERLAY_NAME` and `AOS_OVERLAY_STATE` (where it writes,
50
+ kept across syncs, emptied before `install` and deleted on removal; sessions see
51
+ it as `<NAME>_OVERLAY_STATE`). `AGENTS_OVERLAY_DIR` is gone (it is
52
+ `AOS_OVERLAY_ROOT`). `setup_timeout` is now a variant's `timeout`.
53
+ - An overlay with dependencies or a setup is activated only for the digest its last
54
+ preparation succeeded for on this machine (recorded in
55
+ `<store>/overlays/.dotagents-state/<name>/<os>.prepared.json`). One dotagents finds
56
+ at another digest -- an install that failed, a copy made without dotagents, or one
57
+ installed with `--no-setup` -- is refused until `overlays sync` prepares it; a
58
+ failed sync of the digest already prepared keeps it active. A failed `remove`
59
+ phase is reported and the removal goes ahead.
60
+ - An overlay's `env.py` runs as an AOS env script: one `env.<ext>`, chosen in the
61
+ same order, with the overlay's own environment and no arguments, a 60-second
62
+ timeout, printing one JSON object (over one or several lines) or one object per
63
+ line. An overlay's root `env` file is read as a dotenv file -- `NAME=value`
64
+ lines with `${NAME}` substituted, no shell -- not sourced by bash. An overlay's `pre.env.py`,
65
+ `pre.env` and `local.env` mean nothing; the stores keep all of theirs. A store's
66
+ `pre.*` files run before every overlay, its `env.py` / `env` / `local.env` after.
67
+ - An overlay's `rules/<name>.md` files are always-on rules files by default,
68
+ before the ones `rules` lists.
69
+ - `<NAME>_OVERLAY_ROOT` always names the overlay copy in play; an inherited value
70
+ used to hold.
71
+ - The overlays of every store are applied in one composition order, `(priority,
72
+ name)`, as AOS orders them: a project's overlay no longer comes before a user
73
+ store's overlay because it is the project's (a same-named one still shadows the
74
+ store's copy). Every store's own `bin/` and `lib/` lead all the overlays' dirs on
75
+ `PATH` and `PYTHONPATH`, and `dotagents path` and `AGENTS_PYTHONPATH` list them in
76
+ that order.
77
+ - An overlay's root `env` is applied before its `env.py` (which used to run first),
78
+ and its `lib/python/` is on the session's `PYTHONPATH` for every Python, also when
79
+ the store venv layers it (it used to reach only `$AGENTS_PYTHON` then).
80
+ - An overlay's `CONTEXT.md` comes after the stores' `AGENTS.md` in `context`, as AOS
81
+ orders the base context first.
82
+ - Dependencies install by default from `lib/python/requirements.txt` and
83
+ `lib/node/package.json`, on `add` and every `sync`, before setup, into an
84
+ environment: `shared` (the default, one per runtime per store; dotagents' store
85
+ venv layers the shared Python one), a name, or `isolated`, chosen with
86
+ `environment` in a `[[runtime.python]]` / `[[runtime.node]]` variant, which may
87
+ also name another file (`requirements`, `lock` with `lock_digest`, `package`). A
88
+ root `requirements.txt` means nothing by its name, and overlays' packages are no
89
+ longer installed into the venv itself. A requirements file is a lock when every
90
+ requirement has a `--hash` (hashed in part: refused), installed with
91
+ `--require-hashes --no-deps --only-binary=:all:`; a `package.json` with a
92
+ `package-lock.json` beside it installs with `npm ci`, else `npm install`. Every
93
+ install is reported `deps-network`, and an unpinned file `unlocked-dependencies`.
94
+ Overlays of one environment install together and the environment is rebuilt from
95
+ the remaining members on every add, sync and removal; two members pinning one
96
+ package to two versions are both refused, the package named. `lib/node/` goes on
97
+ `NODE_PATH`, each environment's packages after the overlay's `lib/<runtime>/`.
98
+ `[defaults] deps = false` turns the default files off.
99
+ - The installed copy holds exactly the overlay's files, so it keeps the overlay's tree
100
+ digest: the install record moved beside it, to
101
+ `<store>/overlays/.dotagents-install/<name>.json` (with the commit and the tree
102
+ digest), and caches and setup output inside an installed overlay are removed by
103
+ `add` / `sync`. `--prune` is gone, and so are the `.gitignore` / `.ignore` rules
104
+ that protected files inside an install (`dotagents._ignore`).
105
+ - `overlays add` / `sync` refuse an overlay before writing anything when its tree has
106
+ a symbolic link or a name AOS refuses, its git commit holds a link or a submodule,
107
+ or this machine lacks what its `runtime`, setup or scripts need (an OS, a command,
108
+ an interpreter, a Python or Node version). A launcher is made only for python
109
+ scripts; an overlay declaring a script for another interpreter is refused.
110
+ - MCP: a stdio server starts in its overlay's root; `env_passthrough` and
111
+ `headers_env` pass a variable only when the store grants it; a `command` with a
112
+ separator is a path inside the overlay. An overlay with an invalid `[mcp]` table
113
+ declares nothing, instead of stopping `dotagents mcp` from starting.
114
+ - An overlay source refuses `::` in a git location, a host starting with `-`, a git
115
+ URL scheme other than https, http, ssh, git or file, and a `#path` that is not a
116
+ relative path.
117
+
118
+ ### Added
119
+
120
+ - `env`, `env_files` (AOS or dotenv files), `paths` (prepend or append, per OS),
121
+ `env_scripts`, `context`, `skills`, `runtime`, `setup`, `harness` and `defaults` in
122
+ `overlay.cfg`. Each field's defaults come first and what it declares adds to them;
123
+ an entry naming a default's file or directory replaces that default entry, in its
124
+ place; `[defaults]` turns one off (`bin`, `lib`, `env`, `env_scripts`, `setup`,
125
+ `context`, `skills`, `rules = false`; any other key is refused). Env values can be
126
+ secret references, resolved only when granted.
127
+ - Substitution in env values: a text value in `env`, an `aos` or `dotenv` env file
128
+ or an MCP server's `env` reads other variables as `${NAME}` and its operators
129
+ (`${NAME:-default}`, `${NAME:+alt}`, `${#NAME}`, slices, replacements, trims,
130
+ case), `$$` for a `$`. Each value is substituted once, when it is set, in the order
131
+ of application: a `dotenv` file line by line, one mapping's entries against the
132
+ environment from before it, with the overlay's own `AOS_OVERLAY_ROOT`,
133
+ `AOS_OVERLAY_NAME` and `AOS_OVERLAY_STATE` readable. An undefined name without a
134
+ default, or a placeholder reading a variable that holds a secret, refuses the
135
+ overlay's environment; a single-quoted `dotenv` value is kept as written.
136
+ - Pins, grants and settings in a store's registry document (`dotagents.toml`,
137
+ `overlays` form): `[overlays.<name>] pin = "sha256:..."` refuses any other tree
138
+ digest, at install and at every activation; `grants` lets an overlay read a host
139
+ variable, a named secret (`[secrets.<name>]`) or a file under `secrets_dir`;
140
+ `env_scripts = false` stops an overlay's env scripts. A registry entry may be a
141
+ table with a `source`.
142
+ - Weakenings (`unpinned`, `env-sensitive`, `env-passthrough`, `secret-read`,
143
+ `env-script`, `script-not-run`, `setup-network`, `network-not-enforced`,
144
+ `no-timeout`, `unlocked-dependencies`, `insecure-transport`) are reported each
145
+ time an overlay is activated, and by `overlays show`, which also prints the tree
146
+ digest, the pin, what this machine lacks and the declarations.
147
+ - Setup and env scripts run with their interpreter found on `PATH` (never a `.cmd` or
148
+ `.bat`), arguments as a list, and in a process group or job object, so nothing they
149
+ start outlives them. Python run for an overlay keeps its bytecode under
150
+ `<user store>/.cache/pycache` (`PYTHONPYCACHEPREFIX`).
151
+ - `[harness.<id>]`: `context` for that harness, and `skills = false` to keep the
152
+ overlay's skills out of that harness's own skills dir.
153
+ - Git checkouts hold the blobs' bytes (no line-ending or filter conversion), so a
154
+ digest computed here agrees with any other AOS implementation.
155
+
156
+ ### Upgrading an existing store
157
+
158
+ 1. In each overlay you author, rename `overlay.toml` to `overlay.cfg`, and move its
159
+ Python modules from `lib/` to `lib/python/` (fix anything that names the old
160
+ path), and a root `requirements.txt` to `lib/python/requirements.txt` (or declare
161
+ it as `[[runtime.python]] requirements = "requirements.txt"`). Declare what is
162
+ not a default: a `bin/<name>.py` command
163
+ as `[scripts] <name> = "bin/<name>.py"`, `setup_timeout` as a `[[setup]]`
164
+ entry's `timeout`. Make a root `env` file plain `NAME=value` lines (or an
165
+ `env.py`); write a literal `${` in one as `$${`, or single-quote the value. Have
166
+ setup write only into `$AOS_OVERLAY_STATE`, and accept its phase (`install`,
167
+ `sync`, `remove`) as its first argument, exiting 0 for one it does not know.
168
+ 2. Install the new dotagents, then `dotagents overlays sync -g` (and in each project
169
+ with overlays, `dotagents overlays sync`): it installs the `overlay.cfg` overlays,
170
+ moves the install records beside them, builds their dependency environments and
171
+ runs each setup in its `install` phase (nothing is recorded as prepared yet;
172
+ until this sync, an overlay with dependencies or a setup is refused). To drop the
173
+ packages an older dotagents installed into the store venv itself, delete
174
+ `<store>/.pyvenv/` just before this sync, which makes it again; deleting it later
175
+ takes the dependency environments with it, so sync again after.
176
+ 3. Optionally pin what you trust: `dotagents overlays show <name>` prints its digest;
177
+ put it in the store's `dotagents.toml` as `[overlays.<name>] pin = "..."`.
178
+
10
179
  ## [0.8.3] - 2026-10-30
11
180
 
12
181
  ### Added
@@ -1585,7 +1754,9 @@ Patch release: the PATH/POSIX-conversion fix above (the only change since 0.3.0)
1585
1754
  affected module sources (`dotagents.cli`, `duho.presets`) to extracted temp files
1586
1755
  before dispatch; a no-op for a plain install.
1587
1756
 
1588
- [Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.8.3...HEAD
1757
+ [Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.9.1...HEAD
1758
+ [0.9.1]: https://github.com/jose-pr/dotagents/compare/v0.9.0...v0.9.1
1759
+ [0.9.0]: https://github.com/jose-pr/dotagents/compare/v0.8.3...v0.9.0
1589
1760
  [0.8.3]: https://github.com/jose-pr/dotagents/compare/v0.8.2...v0.8.3
1590
1761
  [0.8.2]: https://github.com/jose-pr/dotagents/compare/v0.8.1...v0.8.2
1591
1762
  [0.8.1]: https://github.com/jose-pr/dotagents/compare/v0.8.0...v0.8.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: dotagents-cli
3
- Version: 0.8.3
3
+ Version: 0.9.1
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
@@ -114,8 +114,10 @@ tree: they are swappable payloads, not part of the tool. Name that branch as a r
114
114
  This repo's own working material (decisions, findings, plans) lives **privately** in
115
115
  its untracked `.agents/` — like every project, `.agents/` is never tracked or pushed.
116
116
 
117
- Each overlay's `<name>/overlay.toml` carries a `name`/`description`/`requires`/`routing`
118
- manifest read by the `dotagents overlays` subcommand, which manages overlays by name
117
+ Overlays follow the [Agent Overlay Specification](https://boriken-dev.github.io/agent-overlay-spec/)
118
+ (AOS): each may carry an `overlay.cfg` manifest (`name`/`description`/`requires`/`routing`,
119
+ and what it needs that is not a default: environment, path additions, setup,
120
+ runtime), read by the `dotagents overlays` subcommand, which manages overlays by name
119
121
  (`add`/`remove`/`list`/`sync`/`show`) — see [Managing overlays](#managing-overlays) below.
120
122
 
121
123
  ## Install
@@ -214,13 +216,21 @@ installed first, its `routing`/`rules` merge into `AGENTS.md`'s managed block, a
214
216
  store's shared `skills/` so every agent sees the same skills.
215
217
 
216
218
  - `add` and `sync` keep an installed overlay exactly as its source ships it: changed
217
- files are replaced and files the source does not ship are removed, anything edited
218
- there backed up under `<store>/install_backup/` first. What the `.gitignore` /
219
- `.ignore` at the overlay's root match (setup output, local state) and tool caches are left
220
- alone; `--prune` clears them too. A fresh `add` whose setup script fails is rolled
221
- back.
219
+ files are replaced and everything else is removed (tool caches and setup output
220
+ included), anything edited there backed up under `<store>/install_backup/` first,
221
+ so the copy keeps the overlay's AOS tree digest. A source is refused before
222
+ anything is written when its manifest does not validate, this machine lacks what
223
+ its `runtime` needs, or the store pins it to another digest. A fresh `add` whose
224
+ preparation (dependencies, then setup) fails is rolled back.
225
+ - An overlay's packages install by default: `lib/python/requirements.txt` (a lock when
226
+ every requirement has a `--hash`) and `lib/node/package.json` (locked by the
227
+ `package-lock.json` beside it), on `add` and every `sync`, before setup. They go
228
+ into the store's **shared** environment, a named one, or the overlay's own
229
+ (`[[runtime.python]] environment = "isolated"`); two overlays pinning one package
230
+ to two versions in one environment are both refused, naming the package.
231
+ `[defaults] deps = false` turns this off.
222
232
  - Each store has a Python venv, `<store>/.pyvenv/<version>-<os>-<arch>/`, where skills
223
- run (`$AGENTS_PYTHON`): duho, every overlay's `requirements.txt` and every overlay
233
+ run (`$AGENTS_PYTHON`): duho, the store's shared Python environment and every agent
224
234
  `lib/` import there, layered project > user > system. pip comes from the
225
235
  interpreter, else its pinned wheel (cache, `AGENTS_PIP_SOURCE`, your index mirror,
226
236
  or a `.pyz` built `--with-pip`).
@@ -233,24 +243,29 @@ store's shared `skills/` so every agent sees the same skills.
233
243
  - `list` and `show` flag a `requires` no installed overlay provides; `show` names the
234
244
  repo an installed overlay came from.
235
245
 
236
- **Overlay setup scripts.** An overlay may ship an **idempotent** `setup.py` at its root
237
- (the recommended form: it runs under the same Python that runs dotagents, so it works on
238
- every OS). After `add`/`sync` copies the overlay
239
- in, dotagents runs the script automatically — so anything a human would otherwise
240
- hand-follow (PATH/lib wiring, self-registration) is one script the tool runs, not a doc.
241
- Presence of the script is the opt-in; skip it with `--no-setup`. The contract for
242
- authors:
243
-
244
- - **Idempotent** — safe to run on every `add`/`sync`; check-then-act, never blindly append.
245
- - **cwd** is the installed overlay dir (`<store>/overlays/<name>/`), so reference
246
- your own files by relative path.
247
- - **Env** carries `AGENTS_HOME` (the user store — never hardcode `~/.agents`),
248
- `AGENTS_SCOPE_ROOT` (the store the overlay is installed into: the user store with
249
- `-g`, the project's `.agents` otherwise), `AGENTS_SCOPE` (`user` or `project`) and
250
- `AGENTS_OVERLAY_DIR` (your own installed dir).
251
- - A **non-zero exit fails the install** with a clear error (not a silent skip). For any
252
- outward or irreversible action the *script* must confirm first — the runner invokes a
253
- script you chose to install; it does not second-guess it.
246
+ **Overlay setup.** An overlay is activated only for the digest its last preparation
247
+ (dependencies, then setup) succeeded for on this machine; `overlays sync` prepares it.
248
+ An overlay's setup is the `[[setup]]` variant its `overlay.cfg`
249
+ declares for this OS (interpreter, args, timeout, network), else one `setup.<ext>` at its
250
+ root, the first this machine can run (`.py`, `.js`, `.mjs`, `.cjs`, then `.ps1` on
251
+ Windows, `.bash`, `.sh` elsewhere), taken to need the network. dotagents runs it
252
+ after `add`/`sync` copies the overlay in and before `remove` deletes it, telling it the
253
+ **phase** as its first argument and `$AOS_SETUP_PHASE`: `install` the first time, `sync`
254
+ on every add or sync after that, `remove` on removal. `--no-setup` skips it. The
255
+ contract for authors:
256
+
257
+ - **Idempotent**, and a phase it does not know is success with nothing to do (exit 0).
258
+ - An `install` or `sync` that fails keeps the overlay from being activated until a
259
+ setup succeeds; a `remove` that fails is reported and the removal goes ahead.
260
+ - **cwd** is the installed overlay root; **write only into `$AOS_OVERLAY_STATE`**, a
261
+ directory outside the root, kept across syncs and deleted on removal, that sessions
262
+ see as `$<NAME>_OVERLAY_STATE`.
263
+ - **Env** is your environment, every overlay's root variable, the overlay's own
264
+ declarations, `AOS_OVERLAY_ROOT` / `AOS_OVERLAY_NAME` / `AOS_OVERLAY_STATE`, and
265
+ `AGENTS_HOME` (the user store — never hardcode `~/.agents`), `AGENTS_SCOPE_ROOT`,
266
+ `AGENTS_SCOPE`.
267
+ - A **non-zero exit or the timeout fails the install** with a clear error, and
268
+ everything the step started is stopped with it.
254
269
 
255
270
  ### Downloadable `dotagents.pyz`
256
271
 
@@ -55,8 +55,10 @@ tree: they are swappable payloads, not part of the tool. Name that branch as a r
55
55
  This repo's own working material (decisions, findings, plans) lives **privately** in
56
56
  its untracked `.agents/` — like every project, `.agents/` is never tracked or pushed.
57
57
 
58
- Each overlay's `<name>/overlay.toml` carries a `name`/`description`/`requires`/`routing`
59
- manifest read by the `dotagents overlays` subcommand, which manages overlays by name
58
+ Overlays follow the [Agent Overlay Specification](https://boriken-dev.github.io/agent-overlay-spec/)
59
+ (AOS): each may carry an `overlay.cfg` manifest (`name`/`description`/`requires`/`routing`,
60
+ and what it needs that is not a default: environment, path additions, setup,
61
+ runtime), read by the `dotagents overlays` subcommand, which manages overlays by name
60
62
  (`add`/`remove`/`list`/`sync`/`show`) — see [Managing overlays](#managing-overlays) below.
61
63
 
62
64
  ## Install
@@ -155,13 +157,21 @@ installed first, its `routing`/`rules` merge into `AGENTS.md`'s managed block, a
155
157
  store's shared `skills/` so every agent sees the same skills.
156
158
 
157
159
  - `add` and `sync` keep an installed overlay exactly as its source ships it: changed
158
- files are replaced and files the source does not ship are removed, anything edited
159
- there backed up under `<store>/install_backup/` first. What the `.gitignore` /
160
- `.ignore` at the overlay's root match (setup output, local state) and tool caches are left
161
- alone; `--prune` clears them too. A fresh `add` whose setup script fails is rolled
162
- back.
160
+ files are replaced and everything else is removed (tool caches and setup output
161
+ included), anything edited there backed up under `<store>/install_backup/` first,
162
+ so the copy keeps the overlay's AOS tree digest. A source is refused before
163
+ anything is written when its manifest does not validate, this machine lacks what
164
+ its `runtime` needs, or the store pins it to another digest. A fresh `add` whose
165
+ preparation (dependencies, then setup) fails is rolled back.
166
+ - An overlay's packages install by default: `lib/python/requirements.txt` (a lock when
167
+ every requirement has a `--hash`) and `lib/node/package.json` (locked by the
168
+ `package-lock.json` beside it), on `add` and every `sync`, before setup. They go
169
+ into the store's **shared** environment, a named one, or the overlay's own
170
+ (`[[runtime.python]] environment = "isolated"`); two overlays pinning one package
171
+ to two versions in one environment are both refused, naming the package.
172
+ `[defaults] deps = false` turns this off.
163
173
  - 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
174
+ run (`$AGENTS_PYTHON`): duho, the store's shared Python environment and every agent
165
175
  `lib/` import there, layered project > user > system. pip comes from the
166
176
  interpreter, else its pinned wheel (cache, `AGENTS_PIP_SOURCE`, your index mirror,
167
177
  or a `.pyz` built `--with-pip`).
@@ -174,24 +184,29 @@ store's shared `skills/` so every agent sees the same skills.
174
184
  - `list` and `show` flag a `requires` no installed overlay provides; `show` names the
175
185
  repo an installed overlay came from.
176
186
 
177
- **Overlay setup scripts.** An overlay may ship an **idempotent** `setup.py` at its root
178
- (the recommended form: it runs under the same Python that runs dotagents, so it works on
179
- every OS). After `add`/`sync` copies the overlay
180
- in, dotagents runs the script automatically — so anything a human would otherwise
181
- hand-follow (PATH/lib wiring, self-registration) is one script the tool runs, not a doc.
182
- Presence of the script is the opt-in; skip it with `--no-setup`. The contract for
183
- authors:
184
-
185
- - **Idempotent** — safe to run on every `add`/`sync`; check-then-act, never blindly append.
186
- - **cwd** is the installed overlay dir (`<store>/overlays/<name>/`), so reference
187
- your own files by relative path.
188
- - **Env** carries `AGENTS_HOME` (the user store — never hardcode `~/.agents`),
189
- `AGENTS_SCOPE_ROOT` (the store the overlay is installed into: the user store with
190
- `-g`, the project's `.agents` otherwise), `AGENTS_SCOPE` (`user` or `project`) and
191
- `AGENTS_OVERLAY_DIR` (your own installed dir).
192
- - A **non-zero exit fails the install** with a clear error (not a silent skip). For any
193
- outward or irreversible action the *script* must confirm first — the runner invokes a
194
- script you chose to install; it does not second-guess it.
187
+ **Overlay setup.** An overlay is activated only for the digest its last preparation
188
+ (dependencies, then setup) succeeded for on this machine; `overlays sync` prepares it.
189
+ An overlay's setup is the `[[setup]]` variant its `overlay.cfg`
190
+ declares for this OS (interpreter, args, timeout, network), else one `setup.<ext>` at its
191
+ root, the first this machine can run (`.py`, `.js`, `.mjs`, `.cjs`, then `.ps1` on
192
+ Windows, `.bash`, `.sh` elsewhere), taken to need the network. dotagents runs it
193
+ after `add`/`sync` copies the overlay in and before `remove` deletes it, telling it the
194
+ **phase** as its first argument and `$AOS_SETUP_PHASE`: `install` the first time, `sync`
195
+ on every add or sync after that, `remove` on removal. `--no-setup` skips it. The
196
+ contract for authors:
197
+
198
+ - **Idempotent**, and a phase it does not know is success with nothing to do (exit 0).
199
+ - An `install` or `sync` that fails keeps the overlay from being activated until a
200
+ setup succeeds; a `remove` that fails is reported and the removal goes ahead.
201
+ - **cwd** is the installed overlay root; **write only into `$AOS_OVERLAY_STATE`**, a
202
+ directory outside the root, kept across syncs and deleted on removal, that sessions
203
+ see as `$<NAME>_OVERLAY_STATE`.
204
+ - **Env** is your environment, every overlay's root variable, the overlay's own
205
+ declarations, `AOS_OVERLAY_ROOT` / `AOS_OVERLAY_NAME` / `AOS_OVERLAY_STATE`, and
206
+ `AGENTS_HOME` (the user store — never hardcode `~/.agents`), `AGENTS_SCOPE_ROOT`,
207
+ `AGENTS_SCOPE`.
208
+ - A **non-zero exit or the timeout fails the install** with a clear error, and
209
+ everything the step started is stopped with it.
195
210
 
196
211
  ### Downloadable `dotagents.pyz`
197
212
 
@@ -1,7 +1,15 @@
1
1
  # Authoring an overlay
2
2
 
3
3
  An overlay is just a directory with the files you want installed into a scope, plus an
4
- optional `overlay.toml` manifest. Anyone can write one; name its parent directory (a
4
+ optional `overlay.cfg` manifest: an
5
+ [AOS](https://boriken-dev.github.io/agent-overlay-spec/) overlay, readable by any
6
+ consumer of the format. The basics need no manifest: `bin/` goes on `PATH`,
7
+ `lib/python/` on `PYTHONPATH`, `skills/<name>/SKILL.md` are skills, `CONTEXT.md` is
8
+ context, `rules/<name>.md` are always-on rules, an `env` file (dotenv) and one
9
+ `env.<ext>` set variables, and one `setup.<ext>` is the setup. Declare only what is
10
+ not a default -- a declaration adds to the defaults, and one naming a default's file
11
+ replaces that default -- and turn a default off in `[defaults]` (`bin`, `lib`, `env`,
12
+ `env_scripts`, `setup`, `context`, `skills`, `rules = false`). Anyone can write one; name its parent directory (a
5
13
  directory of overlays), a registry, or a git repo with `--repo` — see the
6
14
  [overlays guide](overlays.md). Keep the source outside `<store>/overlays/`:
7
15
  `overlays remove` deletes the installed directory outright.
@@ -10,12 +18,12 @@ directory of overlays), a registry, or a git repo with `--repo` — see the
10
18
 
11
19
  ```
12
20
  my-overlay/
13
- overlay.toml
21
+ overlay.cfg
14
22
  kb/MY_TOPIC.md
15
23
  ```
16
24
 
17
25
  ```toml
18
- # my-overlay/overlay.toml
26
+ # my-overlay/overlay.cfg (TOML; `#!json` or `#!yaml` on the first line for those)
19
27
  name = "my-overlay"
20
28
  description = "My team's conventions for topic X."
21
29
  routing = [
@@ -64,37 +72,70 @@ yours needs it.
64
72
 
65
73
  ## Libraries and launchers
66
74
 
67
- Put importable Python in `lib/`. Every Python a session starts sees every overlay's
68
- `lib/` on `PYTHONPATH` (`dotagents env` puts them there, highest precedence first,
69
- and lists them in `$AGENTS_PYTHONPATH`), so a skill script or another overlay can
70
- `import` your module. So can your setup script and your command modules, which
71
- dotagents starts with the libs in place whatever shell it runs from. A `lib/` module
72
- comes before site-packages and the standard library: do not reuse a package name you
73
- do not mean to replace.
75
+ Put importable Python in `lib/python/` (a bare `lib/` means nothing). Every Python a
76
+ session starts sees it on `PYTHONPATH` (prepended, and listed in
77
+ `$AGENTS_PYTHONPATH`), so a skill script or another overlay can `import` your module.
78
+ So can your command modules, which dotagents starts with the libs in place whatever
79
+ shell it runs from, and the setup of an overlay that `requires` yours. Another
80
+ directory goes there with a path addition:
74
81
 
75
- ## Commands on PATH: `bin/*.py` and `[scripts]`
82
+ ```toml
83
+ [[paths]]
84
+ variable = "PYTHONPATH"
85
+ path = "src"
86
+ position = "append" # or "prepend", the default
87
+ os = ["linux", "macos"] # optional
88
+ ```
89
+
90
+ An overlay's packages are `lib/python/requirements.txt` and `lib/node/package.json`,
91
+ installed by default on `add` and every `sync`, before setup. A requirements file is a
92
+ lock when every requirement carries a `--hash` (one hashed in part is refused); a
93
+ `package.json` is locked by the `package-lock.json` beside it (`npm ci`; without it
94
+ `npm install`, reported `unlocked-dependencies`). A variant can name another file or
95
+ another environment:
96
+
97
+ ```toml
98
+ [[runtime.python]]
99
+ version = "3.9"
100
+ requirements = "deps/requirements.txt" # or lock = "locks/all.txt" + lock_digest = "sha256:..."
101
+ environment = "isolated" # "shared" (default), a name, or "isolated"
76
102
 
77
- A Python command needs no launcher of your own. Every top-level `bin/<name>.py`
78
- gets one named `<name>`: `<name>.exe` on Windows (distlib's `ScriptMaker`, the
103
+ [[runtime.node]]
104
+ package = "web/package.json"
105
+ ```
106
+
107
+ Overlays in one shared or named environment install together; if two pin one package
108
+ to two versions, neither is activated. Choose `isolated` (or a name of your own) to
109
+ keep yours apart. `lib/python/` is on `PYTHONPATH` and `lib/node/` on `NODE_PATH`,
110
+ each before the environment's packages; `[defaults] deps = false` turns the default
111
+ files off.
112
+
113
+ ## Commands on PATH: `[scripts]`
114
+
115
+ A Python command needs no launcher of your own. Name it under `[scripts]` and it
116
+ gets one named after the key; `bin/` itself is only on `PATH`, and no file there is a
117
+ command by its name. Each launcher is `<name>.exe` on Windows (distlib's `ScriptMaker`, the
79
118
  launcher pip gives console scripts) and a `/bin/sh` script elsewhere, made in the
80
119
  agents' venv, in `<venv>/overlays/`, whenever `overlays add` / `sync` / `remove` or
81
120
  `init` brings the venv up to date. `dotagents env` puts that directory first on
82
- `PATH` for the venv `$AGENTS_PYTHON` names, so `bin/curl.py` answers to `curl`
83
- ahead of the system's, and drops any other venv's.
121
+ `PATH` for the venv `$AGENTS_PYTHON` names, so with `curl = "bin/curl.py"` the
122
+ overlay's `curl` answers ahead of the system's, and drops any other venv's.
84
123
 
85
- The launcher runs your script under the venv's interpreter, as `python
86
- bin/<name>.py` would, found when it runs through `$<NAME>_OVERLAY_ROOT`: editing
87
- the script or moving the store needs nothing regenerated, only a new interpreter
88
- does. Unset, or with the script missing, it exits 2 and says so. A file whose name
89
- starts with `_` is not a command. Name other scripts, rename one, or opt one out
90
- in `overlay.toml`:
124
+ The launcher runs your script under the venv's interpreter, as `python <script>`
125
+ would, found when it runs through `$<NAME>_OVERLAY_ROOT`: editing the script or
126
+ moving the store needs nothing regenerated, only a new interpreter does. Unset, or
127
+ with the script missing, it exits 2 and says so.
91
128
 
92
129
  ```toml
93
130
  [scripts]
94
- tool = "lib/tool/main.py" # a launcher `tool` for another path
95
- helper = false # none for bin/helper.py
131
+ curl = "bin/curl.py"
132
+ tool = "lib/tool/main.py"
133
+ check = { path = "tools/check.py", interpreter = "python", os = ["windows"] }
96
134
  ```
97
135
 
136
+ dotagents launches python scripts; an overlay naming another interpreter for a
137
+ script is refused by `overlays add`.
138
+
98
139
  Two overlays with one script name is an error naming both. A launcher no overlay
99
140
  has any more is deleted at the next sync.
100
141
 
@@ -108,23 +149,61 @@ for what it starts, if anything needs the libs: its own `lib/`, then
108
149
  `$AGENTS_PYTHONPATH`, then the caller's, leaving empty parts out (an empty entry
109
150
  means the current directory). The net overlay's `bin/curl.py` does this.
110
151
 
111
- ## Setup scripts
112
-
113
- Ship an idempotent `setup.py` at the overlay root to run install-time wiring
114
- automatically — the recommended, OS-agnostic form (it runs under the same Python as
115
- dotagents, so it works on every platform). See the contract in
116
- [Overlays → Setup scripts](overlays.md#setup-scripts). The essentials:
117
-
118
- - idempotent, check-then-act;
119
- - cwd is your installed overlay dir;
120
- - the environment is the scope's assembled `dotagents env` (every overlay's `lib/` on
121
- `PYTHONPATH`, `bin/` on `PATH`), plus the user store (`AGENTS_HOME`), the store you are installed
122
- into (`AGENTS_SCOPE_ROOT`, with `AGENTS_SCOPE` = `user` / `project`) and your own
123
- installed dir (`AGENTS_OVERLAY_DIR`) — never hardcode a home path;
124
- - it has 300 seconds unless `setup_timeout` in `overlay.toml` (or the user's
125
- `--setup-timeout`) says otherwise; `0` means no limit;
152
+ ## Environment
153
+
154
+ An `env` file at the root (`NAME=value` lines, optionally `export `; `${NAME}` is
155
+ substituted from the lines above and the environment, a single-quoted value is kept as
156
+ written)
157
+ and an `env.py` (or `.js`, `.mjs`, `.cjs`, `.ps1` on Windows, `.bash`, `.sh` elsewhere: the first this machine can run) set your
158
+ overlay's variables by default; `[defaults] env = false` turns off the `env` file
159
+ and `env_scripts = false` the script. The script prints one JSON object (across
160
+ several lines if it likes) or one per line (`{"NAME": "value"}`, `null` to unset),
161
+ and gets no arguments unless an `[[env_scripts]]` entry naming it gives some.
162
+ Static values are better declared:
163
+
164
+ ```toml
165
+ [env]
166
+ TOOL_MODE = "read-only"
167
+ TOOL_CONFIG = { path = "conf/tool.toml" } # an absolute path in the overlay
168
+ SYSHTTP_PREFIX = { value = "AGENTS_", if_unset = true }
169
+ DOCS_TOKEN = { provider = "env", key = "DOCS_TOKEN" } # needs the store's grant
170
+ ```
171
+
172
+ No overlay sets `AOS_*`, `*_OVERLAY_ROOT` or `*_OVERLAY_STATE`. A secret is never a
173
+ value in the overlay: reference it, and the user grants it (see
174
+ [Overlays → Pins, grants and env scripts](overlays.md#pins-grants-and-env-scripts-the-stores-own-settings)).
175
+
176
+ ## Setup
177
+
178
+ A `setup.py` (or `.js`, `.mjs`, `.cjs`, `.ps1` on Windows, `.bash`, `.sh` elsewhere) at the root is your setup -- taken to need the network unless a `[[setup]]` entry naming it says `network = false` -- or declare
179
+ variants per OS with `[[setup]]`. See the contract in
180
+ [Overlays → Setup](overlays.md#setup). The essentials:
181
+
182
+ - idempotent; it gets the phase as its first argument and `$AOS_SETUP_PHASE`:
183
+ `install` the first time, `sync` on every add or sync after that, `remove` before
184
+ the overlay is deleted; a phase it does not know is success (exit 0); your
185
+ dependencies are installed before it runs;
186
+ - cwd is your installed overlay root; write only into `$AOS_OVERLAY_STATE`, kept
187
+ across syncs;
188
+ - the environment is the user's, the overlays' root variables, your own declarations,
189
+ `AOS_OVERLAY_ROOT` / `_NAME` / `_STATE`, the user store (`AGENTS_HOME`) and the
190
+ store you are installed into (`AGENTS_SCOPE_ROOT`, `AGENTS_SCOPE`);
191
+ - 300 seconds unless the variant's `timeout` (or the user's `--setup-timeout`) says
192
+ otherwise; `0` means no limit;
193
+ - declare `network = true` when it needs the network: it is reported;
126
194
  - a non-zero exit fails the install loudly; confirm any irreversible action yourself.
127
195
 
196
+ ## Needs
197
+
198
+ Say what must exist where your overlay goes; `overlays add` refuses a machine that
199
+ lacks it, naming what is missing:
200
+
201
+ ```toml
202
+ [runtime]
203
+ os = ["linux", "macos", "windows"]
204
+ commands = ["git", { name = "gh", os = ["linux", "macos"] }]
205
+ ```
206
+
128
207
  ## Custom commands
129
208
 
130
209
  A **command module** is a `*.py` file defining a `duho` command class with a
@@ -195,7 +274,8 @@ a good tool:
195
274
  ## Skills
196
275
 
197
276
  Put `skills/<skill-name>/` directories in your overlay to publish shared skills into
198
- the scope on install. See [Overlays → Skills](overlays.md#skills).
277
+ the scope on install (`skills = [...]` lists them when not all are). See
278
+ [Overlays → Skills](overlays.md#skills).
199
279
 
200
280
  A skill that relies on commands says so, in its own text: which `dotagents` commands
201
281
  it uses, that they are available as MCP tools (`dotagents.<command>`) when the