dotagents-cli 0.8.2__tar.gz → 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/CHANGELOG.md +179 -1
  2. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/PKG-INFO +46 -28
  3. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/README.md +41 -26
  4. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/guide/authoring.md +119 -39
  5. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/guide/commands.md +68 -49
  6. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/guide/install.md +11 -6
  7. dotagents_cli-0.9.0/docs/guide/overlays.md +520 -0
  8. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/pyproject.toml +4 -3
  9. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/AGENTS.md +453 -152
  10. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/__init__.py +1 -1
  11. dotagents_cli-0.9.0/src/dotagents/_activate.py +231 -0
  12. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_agents.py +2 -1
  13. dotagents_cli-0.9.0/src/dotagents/_aos.py +2492 -0
  14. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_context.py +39 -27
  15. dotagents_cli-0.9.0/src/dotagents/_deps.py +393 -0
  16. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_env.py +417 -134
  17. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_launchers.py +6 -5
  18. dotagents_cli-0.9.0/src/dotagents/_mcp_gateway.py +116 -0
  19. dotagents_cli-0.9.0/src/dotagents/_mcp_gateway_clients.py +402 -0
  20. dotagents_cli-0.9.0/src/dotagents/_mcp_gateway_config.py +215 -0
  21. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_overlay/dotagents/templates/AGENTS.md +2 -2
  22. dotagents_cli-0.9.0/src/dotagents/_overlays.py +990 -0
  23. dotagents_cli-0.9.0/src/dotagents/_policy.py +189 -0
  24. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_pyvenv.py +98 -64
  25. dotagents_cli-0.9.0/src/dotagents/_run.py +228 -0
  26. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_scope.py +14 -5
  27. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_skills.py +26 -6
  28. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_sources.py +90 -10
  29. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/cli/__init__.py +25 -6
  30. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/cli/build_pyz.py +3 -2
  31. dotagents_cli-0.9.0/src/dotagents/cli/mcp.py +36 -0
  32. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/cli/overlays.py +473 -125
  33. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/cli/path.py +5 -3
  34. dotagents_cli-0.9.0/tests/aos_vectors/README.md +31 -0
  35. dotagents_cli-0.9.0/tests/aos_vectors/REVISION +1 -0
  36. dotagents_cli-0.9.0/tests/aos_vectors/compose.json +1998 -0
  37. dotagents_cli-0.9.0/tests/aos_vectors/digest.json +641 -0
  38. dotagents_cli-0.9.0/tests/aos_vectors/effective.json +5210 -0
  39. dotagents_cli-0.9.0/tests/aos_vectors/names.json +192 -0
  40. dotagents_cli-0.9.0/tests/aos_vectors/reading.json +2019 -0
  41. dotagents_cli-0.9.0/tests/aos_vectors/source.json +269 -0
  42. dotagents_cli-0.9.0/tests/aos_vectors/validation.json +2052 -0
  43. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/conftest.py +5 -4
  44. dotagents_cli-0.9.0/tests/test_aos_consumer.py +526 -0
  45. dotagents_cli-0.9.0/tests/test_aos_vectors.py +333 -0
  46. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_audit_leak.py +2 -2
  47. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_cli_main.py +5 -4
  48. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_cmds_discovery.py +6 -4
  49. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_context.py +24 -7
  50. dotagents_cli-0.9.0/tests/test_deps.py +212 -0
  51. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_env.py +82 -14
  52. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_env_regressions.py +1 -1
  53. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_env_safety.py +7 -6
  54. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_fix_env.py +3 -0
  55. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_fix_overlays.py +57 -58
  56. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_fix_scope_context.py +9 -4
  57. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_fix_skills_adapters.py +11 -3
  58. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_git_ssl_revoke.py +4 -1
  59. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_init_base.py +1 -1
  60. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_launchers.py +37 -30
  61. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_local_additions.py +18 -2
  62. dotagents_cli-0.9.0/tests/test_mcp.py +373 -0
  63. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_no_internal_labels.py +5 -0
  64. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_overlay_libs.py +20 -11
  65. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_overlays_cli.py +42 -22
  66. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_overlays_command.py +199 -38
  67. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_path_timeout_frontmatter.py +41 -19
  68. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_pyvenv_core.py +27 -21
  69. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_sources.py +13 -13
  70. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_sources_uri.py +4 -4
  71. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tools/audit.py +21 -15
  72. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tools/pyz_smoke.sh +1 -1
  73. dotagents_cli-0.8.2/docs/guide/overlays.md +0 -295
  74. dotagents_cli-0.8.2/src/dotagents/_ignore.py +0 -146
  75. dotagents_cli-0.8.2/src/dotagents/_overlays.py +0 -1226
  76. dotagents_cli-0.8.2/tests/test_ignore.py +0 -58
  77. dotagents_cli-0.8.2/tests/test_mcp.py +0 -60
  78. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/.gitignore +0 -0
  79. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/LICENSE +0 -0
  80. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/agents.md +0 -0
  81. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/cli.md +0 -0
  82. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/commands.md +0 -0
  83. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/context.md +0 -0
  84. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/env.md +0 -0
  85. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/fs.md +0 -0
  86. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/hooks.md +0 -0
  87. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/merge.md +0 -0
  88. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/overlays.md +0 -0
  89. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/reference.md +0 -0
  90. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/resources.md +0 -0
  91. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/scope.md +0 -0
  92. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/skills.md +0 -0
  93. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/sources.md +0 -0
  94. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/api/wrappers.md +0 -0
  95. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/changelog.md +0 -0
  96. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/guide/private-sync.md +0 -0
  97. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/docs/index.md +0 -0
  98. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/install.py +0 -0
  99. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/mkdocs.yml +0 -0
  100. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/__main__.py +0 -0
  101. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_fs.py +0 -0
  102. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_hooks.py +0 -0
  103. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_merge.py +0 -0
  104. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_overlay/dotagents/cmds/findings.py +0 -0
  105. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_overlay/dotagents/cmds/launch.py +0 -0
  106. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_overlay/dotagents/hooks/preinvocation_antigravity_context.py +0 -0
  107. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_overlay/dotagents/hooks/pretooluse_codex_env.py +0 -0
  108. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_overlay/dotagents/hooks/sessionstart_codex_context.py +0 -0
  109. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_overlay/dotagents/templates/PROJECT.md +0 -0
  110. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_pipwheel.py +0 -0
  111. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_resources.py +0 -0
  112. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/_wrappers.py +0 -0
  113. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/cli/_common.py +0 -0
  114. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/cli/about.py +0 -0
  115. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/cli/context.py +0 -0
  116. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/cli/env.py +0 -0
  117. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/cli/init.py +0 -0
  118. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/src/dotagents/py.typed +0 -0
  119. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/_helpers.py +0 -0
  120. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/_shell.py +0 -0
  121. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_about.py +0 -0
  122. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_agents.py +0 -0
  123. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_api_header.py +0 -0
  124. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_build_pyz.py +0 -0
  125. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_cloud_setup.py +0 -0
  126. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_env_cli_scope.py +0 -0
  127. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_env_format.py +0 -0
  128. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_env_into.py +0 -0
  129. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_findings_cmd.py +0 -0
  130. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_fix_adapters.py +0 -0
  131. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_fix_cli.py +0 -0
  132. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_fix_hooks.py +0 -0
  133. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_fix_init.py +0 -0
  134. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_fix_packaging.py +0 -0
  135. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_hooks.py +0 -0
  136. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_last_mile.py +0 -0
  137. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_launch_cmd.py +0 -0
  138. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_pipwheel.py +0 -0
  139. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_powershell_env_hook.py +0 -0
  140. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_quoting_injection_safety.py +0 -0
  141. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_scope.py +0 -0
  142. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_wire_hooks.py +0 -0
  143. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tests/test_wrappers.py +0 -0
  144. {dotagents_cli-0.8.2 → dotagents_cli-0.9.0}/tools/cloud-setup.sh +0 -0
@@ -7,6 +7,182 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.0] - 2026-11-04
11
+
12
+ dotagents implements the [Agent Overlay Specification](https://boriken-dev.github.io/agent-overlay-spec/)
13
+ (AOS, edition `0.1.0-draft`) and passes its conformance vectors.
14
+
15
+ ### Changed (breaking)
16
+
17
+ - An overlay's manifest is `overlay.cfg` (TOML by default; `#!json` or `#!yaml` on
18
+ its first line for JSON or YAML, the latter with the `yaml` extra). `overlay.toml`
19
+ is not read any more; an overlay that still has one gets a warning naming it.
20
+ - A manifest that does not validate against AOS is ignored whole, with a warning
21
+ naming where it is wrong, and `overlays add` / `sync` refuse it. It used to keep
22
+ its valid fields and drop the others. The small built-in TOML reader is gone: below
23
+ Python 3.11 manifests need `tomli` (a declared dependency, vendored in the `.pyz`).
24
+ - An overlay's Python modules go in `lib/python/`, prepended to `PYTHONPATH`; a
25
+ bare `lib/` is not on any path any more. `bin/` and `lib/python/` count only when
26
+ they hold a file.
27
+ - A `bin/<name>.py` no longer gets a launcher by its name: a command is a
28
+ `[scripts]` entry (`curl = "bin/curl.py"`). `bin/` itself stays on `PATH`.
29
+ - An overlay's setup is the first `[[setup]]` variant it declares for the OS, else
30
+ one `setup.<ext>` at its root -- the first, in the order `.py`, `.js`, `.mjs`,
31
+ `.cjs`, then `.ps1` on Windows, then `.bash`, `.sh` elsewhere, that this machine
32
+ can run -- taken to need the network. It is told its phase as its first argument
33
+ and `AOS_SETUP_PHASE`: `install` on the first `add`, `sync` on every `add` or
34
+ `sync` after one succeeded, and `remove` when `overlays remove` deletes the
35
+ overlay (new: setup used to run with no argument, and never on removal). A script
36
+ must treat a phase it does not know as success. It runs after the overlay's
37
+ dependencies are installed, in the overlay's own environment, with
38
+ `AOS_OVERLAY_ROOT`, `AOS_OVERLAY_NAME` and `AOS_OVERLAY_STATE` (where it writes,
39
+ kept across syncs, emptied before `install` and deleted on removal; sessions see
40
+ it as `<NAME>_OVERLAY_STATE`). `AGENTS_OVERLAY_DIR` is gone (it is
41
+ `AOS_OVERLAY_ROOT`). `setup_timeout` is now a variant's `timeout`.
42
+ - An overlay with dependencies or a setup is activated only for the digest its last
43
+ preparation succeeded for on this machine (recorded in
44
+ `<store>/overlays/.dotagents-state/<name>/<os>.prepared.json`). One dotagents finds
45
+ at another digest -- an install that failed, a copy made without dotagents, or one
46
+ installed with `--no-setup` -- is refused until `overlays sync` prepares it; a
47
+ failed sync of the digest already prepared keeps it active. A failed `remove`
48
+ phase is reported and the removal goes ahead.
49
+ - An overlay's `env.py` runs as an AOS env script: one `env.<ext>`, chosen in the
50
+ same order, with the overlay's own environment and no arguments, a 60-second
51
+ timeout, printing one JSON object (over one or several lines) or one object per
52
+ line. An overlay's root `env` file is read as a dotenv file -- `NAME=value`
53
+ lines with `${NAME}` substituted, no shell -- not sourced by bash. An overlay's `pre.env.py`,
54
+ `pre.env` and `local.env` mean nothing; the stores keep all of theirs. A store's
55
+ `pre.*` files run before every overlay, its `env.py` / `env` / `local.env` after.
56
+ - An overlay's `rules/<name>.md` files are always-on rules files by default,
57
+ before the ones `rules` lists.
58
+ - `<NAME>_OVERLAY_ROOT` always names the overlay copy in play; an inherited value
59
+ used to hold.
60
+ - The overlays of every store are applied in one composition order, `(priority,
61
+ name)`, as AOS orders them: a project's overlay no longer comes before a user
62
+ store's overlay because it is the project's (a same-named one still shadows the
63
+ store's copy). Every store's own `bin/` and `lib/` lead all the overlays' dirs on
64
+ `PATH` and `PYTHONPATH`, and `dotagents path` and `AGENTS_PYTHONPATH` list them in
65
+ that order.
66
+ - An overlay's root `env` is applied before its `env.py` (which used to run first),
67
+ and its `lib/python/` is on the session's `PYTHONPATH` for every Python, also when
68
+ the store venv layers it (it used to reach only `$AGENTS_PYTHON` then).
69
+ - An overlay's `CONTEXT.md` comes after the stores' `AGENTS.md` in `context`, as AOS
70
+ orders the base context first.
71
+ - Dependencies install by default from `lib/python/requirements.txt` and
72
+ `lib/node/package.json`, on `add` and every `sync`, before setup, into an
73
+ environment: `shared` (the default, one per runtime per store; dotagents' store
74
+ venv layers the shared Python one), a name, or `isolated`, chosen with
75
+ `environment` in a `[[runtime.python]]` / `[[runtime.node]]` variant, which may
76
+ also name another file (`requirements`, `lock` with `lock_digest`, `package`). A
77
+ root `requirements.txt` means nothing by its name, and overlays' packages are no
78
+ longer installed into the venv itself. A requirements file is a lock when every
79
+ requirement has a `--hash` (hashed in part: refused), installed with
80
+ `--require-hashes --no-deps --only-binary=:all:`; a `package.json` with a
81
+ `package-lock.json` beside it installs with `npm ci`, else `npm install`. Every
82
+ install is reported `deps-network`, and an unpinned file `unlocked-dependencies`.
83
+ Overlays of one environment install together and the environment is rebuilt from
84
+ the remaining members on every add, sync and removal; two members pinning one
85
+ package to two versions are both refused, the package named. `lib/node/` goes on
86
+ `NODE_PATH`, each environment's packages after the overlay's `lib/<runtime>/`.
87
+ `[defaults] deps = false` turns the default files off.
88
+ - The installed copy holds exactly the overlay's files, so it keeps the overlay's tree
89
+ digest: the install record moved beside it, to
90
+ `<store>/overlays/.dotagents-install/<name>.json` (with the commit and the tree
91
+ digest), and caches and setup output inside an installed overlay are removed by
92
+ `add` / `sync`. `--prune` is gone, and so are the `.gitignore` / `.ignore` rules
93
+ that protected files inside an install (`dotagents._ignore`).
94
+ - `overlays add` / `sync` refuse an overlay before writing anything when its tree has
95
+ a symbolic link or a name AOS refuses, its git commit holds a link or a submodule,
96
+ or this machine lacks what its `runtime`, setup or scripts need (an OS, a command,
97
+ an interpreter, a Python or Node version). A launcher is made only for python
98
+ scripts; an overlay declaring a script for another interpreter is refused.
99
+ - MCP: a stdio server starts in its overlay's root; `env_passthrough` and
100
+ `headers_env` pass a variable only when the store grants it; a `command` with a
101
+ separator is a path inside the overlay. An overlay with an invalid `[mcp]` table
102
+ declares nothing, instead of stopping `dotagents mcp` from starting.
103
+ - An overlay source refuses `::` in a git location, a host starting with `-`, a git
104
+ URL scheme other than https, http, ssh, git or file, and a `#path` that is not a
105
+ relative path.
106
+
107
+ ### Added
108
+
109
+ - `env`, `env_files` (AOS or dotenv files), `paths` (prepend or append, per OS),
110
+ `env_scripts`, `context`, `skills`, `runtime`, `setup`, `harness` and `defaults` in
111
+ `overlay.cfg`. Each field's defaults come first and what it declares adds to them;
112
+ an entry naming a default's file or directory replaces that default entry, in its
113
+ place; `[defaults]` turns one off (`bin`, `lib`, `env`, `env_scripts`, `setup`,
114
+ `context`, `skills`, `rules = false`; any other key is refused). Env values can be
115
+ secret references, resolved only when granted.
116
+ - Substitution in env values: a text value in `env`, an `aos` or `dotenv` env file
117
+ or an MCP server's `env` reads other variables as `${NAME}` and its operators
118
+ (`${NAME:-default}`, `${NAME:+alt}`, `${#NAME}`, slices, replacements, trims,
119
+ case), `$$` for a `$`. Each value is substituted once, when it is set, in the order
120
+ of application: a `dotenv` file line by line, one mapping's entries against the
121
+ environment from before it, with the overlay's own `AOS_OVERLAY_ROOT`,
122
+ `AOS_OVERLAY_NAME` and `AOS_OVERLAY_STATE` readable. An undefined name without a
123
+ default, or a placeholder reading a variable that holds a secret, refuses the
124
+ overlay's environment; a single-quoted `dotenv` value is kept as written.
125
+ - Pins, grants and settings in a store's registry document (`dotagents.toml`,
126
+ `overlays` form): `[overlays.<name>] pin = "sha256:..."` refuses any other tree
127
+ digest, at install and at every activation; `grants` lets an overlay read a host
128
+ variable, a named secret (`[secrets.<name>]`) or a file under `secrets_dir`;
129
+ `env_scripts = false` stops an overlay's env scripts. A registry entry may be a
130
+ table with a `source`.
131
+ - Weakenings (`unpinned`, `env-sensitive`, `env-passthrough`, `secret-read`,
132
+ `env-script`, `script-not-run`, `setup-network`, `network-not-enforced`,
133
+ `no-timeout`, `unlocked-dependencies`, `insecure-transport`) are reported each
134
+ time an overlay is activated, and by `overlays show`, which also prints the tree
135
+ digest, the pin, what this machine lacks and the declarations.
136
+ - Setup and env scripts run with their interpreter found on `PATH` (never a `.cmd` or
137
+ `.bat`), arguments as a list, and in a process group or job object, so nothing they
138
+ start outlives them. Python run for an overlay keeps its bytecode under
139
+ `<user store>/.cache/pycache` (`PYTHONPYCACHEPREFIX`).
140
+ - `[harness.<id>]`: `context` for that harness, and `skills = false` to keep the
141
+ overlay's skills out of that harness's own skills dir.
142
+ - Git checkouts hold the blobs' bytes (no line-ending or filter conversion), so a
143
+ digest computed here agrees with any other AOS implementation.
144
+
145
+ ### Upgrading an existing store
146
+
147
+ 1. In each overlay you author, rename `overlay.toml` to `overlay.cfg`, and move its
148
+ Python modules from `lib/` to `lib/python/` (fix anything that names the old
149
+ path), and a root `requirements.txt` to `lib/python/requirements.txt` (or declare
150
+ it as `[[runtime.python]] requirements = "requirements.txt"`). Declare what is
151
+ not a default: a `bin/<name>.py` command
152
+ as `[scripts] <name> = "bin/<name>.py"`, `setup_timeout` as a `[[setup]]`
153
+ entry's `timeout`. Make a root `env` file plain `NAME=value` lines (or an
154
+ `env.py`); write a literal `${` in one as `$${`, or single-quote the value. Have
155
+ setup write only into `$AOS_OVERLAY_STATE`, and accept its phase (`install`,
156
+ `sync`, `remove`) as its first argument, exiting 0 for one it does not know.
157
+ 2. Install the new dotagents, then `dotagents overlays sync -g` (and in each project
158
+ with overlays, `dotagents overlays sync`): it installs the `overlay.cfg` overlays,
159
+ moves the install records beside them, builds their dependency environments and
160
+ runs each setup in its `install` phase (nothing is recorded as prepared yet;
161
+ until this sync, an overlay with dependencies or a setup is refused). To drop the
162
+ packages an older dotagents installed into the store venv itself, delete
163
+ `<store>/.pyvenv/` just before this sync, which makes it again; deleting it later
164
+ takes the dependency environments with it, so sync again after.
165
+ 3. Optionally pin what you trust: `dotagents overlays show <name>` prints its digest;
166
+ put it in the store's `dotagents.toml` as `[overlays.<name>] pin = "..."`.
167
+
168
+ ## [0.8.3] - 2026-10-30
169
+
170
+ ### Added
171
+
172
+ - `dotagents mcp` starts the stdio MCP gateway and can forward tools from
173
+ overlay-declared stdio and Streamable HTTP servers. Forwarded names default
174
+ to `<skill-or-server-name>.<tool>`; `--prefix` accepts a `{name}` template.
175
+ `dotagents.mcp.refresh` reloads active overlay declarations and reconnects
176
+ servers without restarting dotagents.
177
+ Overlays declare servers and skill mappings in `overlay.toml` under `[mcp]`;
178
+ Streamable HTTP requires the `mcp-http` extra, and credentials are read from
179
+ named environment variables.
180
+
181
+ ### Changed
182
+
183
+ - Requires duho 0.7.9 (its `ToolProvider` serves the forwarded tools), also in
184
+ the scope venvs and the `.pyz`.
185
+
10
186
  ## [0.8.2] - 2026-10-25
11
187
 
12
188
  ### Fixed
@@ -1567,7 +1743,9 @@ Patch release: the PATH/POSIX-conversion fix above (the only change since 0.3.0)
1567
1743
  affected module sources (`dotagents.cli`, `duho.presets`) to extracted temp files
1568
1744
  before dispatch; a no-op for a plain install.
1569
1745
 
1570
- [Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.8.2...HEAD
1746
+ [Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.9.0...HEAD
1747
+ [0.9.0]: https://github.com/jose-pr/dotagents/compare/v0.8.3...v0.9.0
1748
+ [0.8.3]: https://github.com/jose-pr/dotagents/compare/v0.8.2...v0.8.3
1571
1749
  [0.8.2]: https://github.com/jose-pr/dotagents/compare/v0.8.1...v0.8.2
1572
1750
  [0.8.1]: https://github.com/jose-pr/dotagents/compare/v0.8.0...v0.8.1
1573
1751
  [0.8.0]: https://github.com/jose-pr/dotagents/compare/v0.7.6...v0.8.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: dotagents-cli
3
- Version: 0.8.2
3
+ Version: 0.9.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
@@ -24,7 +24,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
24
  Classifier: Typing :: Typed
25
25
  Requires-Python: >=3.9
26
26
  Requires-Dist: distlib<0.5,>=0.4.0
27
- Requires-Dist: duho<0.8,>=0.7.5
27
+ Requires-Dist: duho<0.8,>=0.7.9
28
28
  Requires-Dist: pathapi<0.2,>=0.1.0
29
29
  Requires-Dist: tomli>=1.1.0; python_version < '3.11'
30
30
  Provides-Extra: dev
@@ -33,12 +33,15 @@ Requires-Dist: hatchling>=1.27; extra == 'dev'
33
33
  Requires-Dist: pathapi-uri<0.2,>=0.1.0; extra == 'dev'
34
34
  Requires-Dist: pytest; extra == 'dev'
35
35
  Requires-Dist: pyyaml; extra == 'dev'
36
+ Requires-Dist: syshttp<0.2,>=0.1.0; extra == 'dev'
36
37
  Provides-Extra: docs
37
38
  Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
38
39
  Requires-Dist: mkdocs>=1.5; extra == 'docs'
39
40
  Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
40
41
  Provides-Extra: http
41
42
  Requires-Dist: pathapi-uri<0.2,>=0.1.0; extra == 'http'
43
+ Provides-Extra: mcp-http
44
+ Requires-Dist: syshttp<0.2,>=0.1.0; extra == 'mcp-http'
42
45
  Provides-Extra: repo
43
46
  Requires-Dist: pathapi-uri<0.2,>=0.1.0; extra == 'repo'
44
47
  Requires-Dist: repopath[uri]<0.2,>=0.1.0; extra == 'repo'
@@ -111,8 +114,10 @@ tree: they are swappable payloads, not part of the tool. Name that branch as a r
111
114
  This repo's own working material (decisions, findings, plans) lives **privately** in
112
115
  its untracked `.agents/` — like every project, `.agents/` is never tracked or pushed.
113
116
 
114
- Each overlay's `<name>/overlay.toml` carries a `name`/`description`/`requires`/`routing`
115
- 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
116
121
  (`add`/`remove`/`list`/`sync`/`show`) — see [Managing overlays](#managing-overlays) below.
117
122
 
118
123
  ## Install
@@ -211,13 +216,21 @@ installed first, its `routing`/`rules` merge into `AGENTS.md`'s managed block, a
211
216
  store's shared `skills/` so every agent sees the same skills.
212
217
 
213
218
  - `add` and `sync` keep an installed overlay exactly as its source ships it: changed
214
- files are replaced and files the source does not ship are removed, anything edited
215
- there backed up under `<store>/install_backup/` first. What the `.gitignore` /
216
- `.ignore` at the overlay's root match (setup output, local state) and tool caches are left
217
- alone; `--prune` clears them too. A fresh `add` whose setup script fails is rolled
218
- 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.
219
232
  - Each store has a Python venv, `<store>/.pyvenv/<version>-<os>-<arch>/`, where skills
220
- 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
221
234
  `lib/` import there, layered project > user > system. pip comes from the
222
235
  interpreter, else its pinned wheel (cache, `AGENTS_PIP_SOURCE`, your index mirror,
223
236
  or a `.pyz` built `--with-pip`).
@@ -230,24 +243,29 @@ store's shared `skills/` so every agent sees the same skills.
230
243
  - `list` and `show` flag a `requires` no installed overlay provides; `show` names the
231
244
  repo an installed overlay came from.
232
245
 
233
- **Overlay setup scripts.** An overlay may ship an **idempotent** `setup.py` at its root
234
- (the recommended form: it runs under the same Python that runs dotagents, so it works on
235
- every OS). After `add`/`sync` copies the overlay
236
- in, dotagents runs the script automatically — so anything a human would otherwise
237
- hand-follow (PATH/lib wiring, self-registration) is one script the tool runs, not a doc.
238
- Presence of the script is the opt-in; skip it with `--no-setup`. The contract for
239
- authors:
240
-
241
- - **Idempotent** — safe to run on every `add`/`sync`; check-then-act, never blindly append.
242
- - **cwd** is the installed overlay dir (`<store>/overlays/<name>/`), so reference
243
- your own files by relative path.
244
- - **Env** carries `AGENTS_HOME` (the user store — never hardcode `~/.agents`),
245
- `AGENTS_SCOPE_ROOT` (the store the overlay is installed into: the user store with
246
- `-g`, the project's `.agents` otherwise), `AGENTS_SCOPE` (`user` or `project`) and
247
- `AGENTS_OVERLAY_DIR` (your own installed dir).
248
- - A **non-zero exit fails the install** with a clear error (not a silent skip). For any
249
- outward or irreversible action the *script* must confirm first — the runner invokes a
250
- 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.
251
269
 
252
270
  ### Downloadable `dotagents.pyz`
253
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