dotagents-cli 0.3.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 (67) hide show
  1. dotagents_cli-0.3.0/.gitignore +36 -0
  2. dotagents_cli-0.3.0/CHANGELOG.md +212 -0
  3. dotagents_cli-0.3.0/LICENSE +21 -0
  4. dotagents_cli-0.3.0/PKG-INFO +291 -0
  5. dotagents_cli-0.3.0/README.md +230 -0
  6. dotagents_cli-0.3.0/build.py +80 -0
  7. dotagents_cli-0.3.0/docs/api/agents.md +3 -0
  8. dotagents_cli-0.3.0/docs/api/cli.md +3 -0
  9. dotagents_cli-0.3.0/docs/api/context.md +3 -0
  10. dotagents_cli-0.3.0/docs/api/env.md +3 -0
  11. dotagents_cli-0.3.0/docs/api/hooks.md +3 -0
  12. dotagents_cli-0.3.0/docs/api/merge.md +3 -0
  13. dotagents_cli-0.3.0/docs/api/overlays.md +3 -0
  14. dotagents_cli-0.3.0/docs/api/reference.md +24 -0
  15. dotagents_cli-0.3.0/docs/api/resolve.md +3 -0
  16. dotagents_cli-0.3.0/docs/api/scope.md +3 -0
  17. dotagents_cli-0.3.0/docs/api/skills.md +3 -0
  18. dotagents_cli-0.3.0/docs/api/sync.md +3 -0
  19. dotagents_cli-0.3.0/docs/changelog.md +3 -0
  20. dotagents_cli-0.3.0/docs/guide/authoring.md +87 -0
  21. dotagents_cli-0.3.0/docs/guide/commands.md +233 -0
  22. dotagents_cli-0.3.0/docs/guide/install.md +54 -0
  23. dotagents_cli-0.3.0/docs/guide/overlays.md +100 -0
  24. dotagents_cli-0.3.0/docs/guide/private-sync.md +75 -0
  25. dotagents_cli-0.3.0/docs/index.md +60 -0
  26. dotagents_cli-0.3.0/install.py +92 -0
  27. dotagents_cli-0.3.0/mkdocs.yml +68 -0
  28. dotagents_cli-0.3.0/pyproject.toml +61 -0
  29. dotagents_cli-0.3.0/src/dotagents/AGENTS.md +125 -0
  30. dotagents_cli-0.3.0/src/dotagents/__init__.py +3 -0
  31. dotagents_cli-0.3.0/src/dotagents/__main__.py +6 -0
  32. dotagents_cli-0.3.0/src/dotagents/_agents.py +627 -0
  33. dotagents_cli-0.3.0/src/dotagents/_context.py +311 -0
  34. dotagents_cli-0.3.0/src/dotagents/_env.py +600 -0
  35. dotagents_cli-0.3.0/src/dotagents/_hooks.py +172 -0
  36. dotagents_cli-0.3.0/src/dotagents/_merge.py +122 -0
  37. dotagents_cli-0.3.0/src/dotagents/_overlay/AGENTS.md +31 -0
  38. dotagents_cli-0.3.0/src/dotagents/_overlay/CLAUDE.md +3 -0
  39. dotagents_cli-0.3.0/src/dotagents/_overlay/README.md +41 -0
  40. dotagents_cli-0.3.0/src/dotagents/_overlay/dotagents/DECISIONS.md +20 -0
  41. dotagents_cli-0.3.0/src/dotagents/_overlay/dotagents/cmds/README.md +46 -0
  42. dotagents_cli-0.3.0/src/dotagents/_overlays.py +412 -0
  43. dotagents_cli-0.3.0/src/dotagents/_resolve.py +81 -0
  44. dotagents_cli-0.3.0/src/dotagents/_scope.py +265 -0
  45. dotagents_cli-0.3.0/src/dotagents/_skills.py +236 -0
  46. dotagents_cli-0.3.0/src/dotagents/_sync.py +72 -0
  47. dotagents_cli-0.3.0/src/dotagents/_wrappers.py +112 -0
  48. dotagents_cli-0.3.0/src/dotagents/cli/__init__.py +354 -0
  49. dotagents_cli-0.3.0/src/dotagents/cli/_common.py +331 -0
  50. dotagents_cli-0.3.0/src/dotagents/cli/build_pyz.py +107 -0
  51. dotagents_cli-0.3.0/src/dotagents/cli/context.py +129 -0
  52. dotagents_cli-0.3.0/src/dotagents/cli/env.py +168 -0
  53. dotagents_cli-0.3.0/src/dotagents/cli/init.py +117 -0
  54. dotagents_cli-0.3.0/src/dotagents/cli/overlays.py +366 -0
  55. dotagents_cli-0.3.0/tests/test_agents.py +184 -0
  56. dotagents_cli-0.3.0/tests/test_audit_leak.py +71 -0
  57. dotagents_cli-0.3.0/tests/test_cmds_discovery.py +330 -0
  58. dotagents_cli-0.3.0/tests/test_context.py +198 -0
  59. dotagents_cli-0.3.0/tests/test_env.py +416 -0
  60. dotagents_cli-0.3.0/tests/test_env_format.py +230 -0
  61. dotagents_cli-0.3.0/tests/test_hooks.py +149 -0
  62. dotagents_cli-0.3.0/tests/test_overlays_command.py +615 -0
  63. dotagents_cli-0.3.0/tests/test_scope.py +126 -0
  64. dotagents_cli-0.3.0/tests/test_wire_hooks.py +439 -0
  65. dotagents_cli-0.3.0/tests/test_wrappers.py +127 -0
  66. dotagents_cli-0.3.0/tools/audit.py +261 -0
  67. dotagents_cli-0.3.0/tools/cloud-setup.sh +294 -0
@@ -0,0 +1,36 @@
1
+ # Private agent config. No trailing slash: `dotagents link-project` makes .agents
2
+ # a symlink, which git treats as a file, so a directory-only `.agents/` would not
3
+ # match it. The design log lives INSIDE .agents/dotagents/ and is private like
4
+ # every other project's (D61, reversing D56); CHANGELOG.md cites no D-numbers.
5
+ .agents
6
+ *.local.md
7
+ CLAUDE.local.md
8
+ .claude/
9
+
10
+ # Python
11
+ __pycache__/
12
+ *.py[cod]
13
+ *.egg-info/
14
+ src/*.egg-info/
15
+ .pytest_cache/
16
+ .ruff_cache/
17
+ .mypy_cache/
18
+ .tox/
19
+ .coverage
20
+ htmlcov/
21
+
22
+ # dotagents CLI package build artifacts (release artifacts, not committed)
23
+ dist/
24
+ *.pyz
25
+ .venv/
26
+ .venv-test/
27
+
28
+ # MkDocs build output
29
+ site/
30
+
31
+ # OS/editor
32
+ .DS_Store
33
+ Thumbs.db
34
+ .idea/
35
+ .vscode/
36
+ _staging/
@@ -0,0 +1,212 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.0] - 2026-07-24
11
+
12
+ ### Changed
13
+
14
+ - **BREAKING** — `dotagents link` / `dotagents sync` are gone from the CLI. They are
15
+ the private-sync workflow's commands, not dotagents' core, so they moved — together
16
+ with the logic behind them (`src/dotagents/_link.py`) — into the opt-in
17
+ **`private-sync` overlay**, and were renamed to say what they act on:
18
+
19
+ dotagents link-project . # was: dotagents link .
20
+ dotagents sync-project -m "msg" # was: dotagents sync -m "msg"
21
+
22
+ Install the overlay to get them back: `dotagents overlays add private-sync --source
23
+ <overlays-checkout>`. A plain dotagents now ships no private-sync workflow at all;
24
+ its whole command surface is `init` / `build-pyz` / `context` / `env` / `overlays`,
25
+ and everything else is discovered from an overlay or from your own `cmds/` modules.
26
+ `tools/cloud-setup.sh` installs the overlay before linking, so the cloud bootstrap
27
+ is unaffected.
28
+ - The bundled `dotagents/cmds/` directory now ships no command module of its own, but
29
+ `init` still creates it: it is the documented drop-in point for your own commands
30
+ (a `README.md` beside it explains the shape and the precedence rules).
31
+
32
+ ### Added
33
+
34
+ - feat: `init` wires agent hooks and links the shared skills dir, for each active
35
+ agent with a published hook schema (today: Claude and Codex). `--no-hooks` skips it.
36
+
37
+ **Claude** (`~/.claude/settings.json`) gets `SessionStart`, which appends
38
+ `dotagents env --diff --format export` to `$CLAUDE_ENV_FILE` and then runs
39
+ `dotagents context` — Claude sources that file before each Bash command and injects
40
+ the hook's stdout into the session context, so both the env layers and the assembled
41
+ context reach the session automatically. It also gets `CwdChanged`, surfacing a
42
+ directory's `AGENTS.md`. The env redirect **appends** and is guarded against an
43
+ unset variable, both as the hooks docs require.
44
+
45
+ **Codex** (`~/.codex/hooks.json`, or `$CODEX_HOME`) gets `SessionStart` running
46
+ `dotagents context`; its hook JSON is structurally identical to Claude's. We write
47
+ `hooks.json` rather than touching your `config.toml` for hooks.
48
+
49
+ Codex's env arrives differently: it has no `$CLAUDE_ENV_FILE` equivalent, reads no
50
+ `.env` files, and has no event that fires before config load, so
51
+ `dotagents init --agents codex` writes a `# dotagents:begin/end` managed block
52
+ containing `[shell_environment_policy].set` into `config.toml`. **Only on an
53
+ explicit `--agents`** — this edits your main config with values that go stale, so
54
+ auto-detection never triggers it. The block is appended and refreshed in place
55
+ (everything outside the markers is untouched) and `set` merges rather than
56
+ replaces. **The values are a static snapshot: re-run `init` after changing your env
57
+ layers.** Identity vars describe the target agent, so initializing from Claude still
58
+ writes `AGENT = "codex"`; `PATH` is excluded, since `set` overrides per subprocess
59
+ and a baked-in `PATH` would replace the inherited one.
60
+
61
+ The merge is additive and idempotent: unrelated keys and hooks you wrote yourself
62
+ survive verbatim, malformed entries are dropped rather than raising, and re-running
63
+ writes nothing.
64
+
65
+ `init` also links `<scope>/skills/` into the agent's config dir, closing the last
66
+ mile for overlay-published skills — publishing only helps if the agent reads that
67
+ directory. Symlink where the OS permits, copy otherwise (a copy is a snapshot;
68
+ re-run `init` to refresh).
69
+
70
+ - feat: `tools/leak_check.py` now also scans commit messages (current branch history)
71
+ for agent-session trailers/URLs — a `Claude-Session:` trailer or `claude.ai/code/session`
72
+ link — and exits 1 on any hit. The trailer is auto-added by the agent harness and
73
+ exposes a session id in public history if it slips through; the pre-existing tracked-file
74
+ scan didn't cover commit messages. `flows/REPO.md` release discipline documents the check
75
+ and the `git filter-branch --msg-filter` remediation for one that already landed.
76
+ - feat: `tools/cloud-setup.sh` step 5 wires `hooks/settings.snippet.json` into the
77
+ user-level `~/.claude/settings.json` (idempotent JSON merge, preserves existing
78
+ settings/hooks). A fresh cloud container has no settings file and nothing else
79
+ created one, so the SessionStart pull/link and Stop sync-back hooks never ran —
80
+ the private repo went stale and session changes were silently never pushed back.
81
+ `kb/PRIVATE_SYNC.md` documents the auto-wiring (manual merge still applies on
82
+ local machines).
83
+
84
+ ### Fixed
85
+
86
+ - fix: `dotagents link`/`sync` never adopt or copy back a `<project>/.agents` that is
87
+ itself a git checkout (`.git` present — dir, or file for worktrees). A hosted-runner
88
+ session that lists the agents repo as a *source* gets it cloned to
89
+ `<project>/.agents` by the harness; first-link adoption then moved that entire
90
+ checkout — `.git`, foreign proxy remote, session branch — into
91
+ `~/.agents/projects/<name>/`, nesting a repo inside the private repo, which a later
92
+ sync's `git add -A` would push as a bare gitlink (and `sync`'s copy-back had the same
93
+ swallow, with `overwrite=True`). Both paths now log a skip and leave the checkout in
94
+ place; `link --force` keeps an escape hatch that backs the checkout up to
95
+ `.agents.bak*` (git state intact) and links the store.
96
+
97
+ - fix: `dotagents sync` now authenticates the private repo directly against github.com
98
+ when `DOTAGENTS_AGENTS_TOKEN` is set — and on a hosted runner that rewrites github
99
+ traffic to a scoped in-session proxy, bypasses the rewrite — so a **standalone**
100
+ `dotagents sync` no longer 403s. Previously only the private-sync Stop hook worked
101
+ (it sources `_agents-git-auth.sh`); a direct CLI run had no bypass, so its pull failed
102
+ (`could not read Password`) and its push returned HTTP 403 through the proxy. The CLI
103
+ now ports that logic: a per-command `-c` credential helper in a normal environment, or
104
+ an isolated `GIT_CONFIG_GLOBAL` (identity + CA bundle preserved) that skips the rewrite
105
+ when one is active. The token is still read from the environment at auth time and never
106
+ written to `.git/config`.
107
+ - fix: `tools/cloud-setup.sh` no longer lets a single container-start clone failure
108
+ permanently disable the environment. The clone often loses a race with egress/proxy
109
+ readiness; previously it `exit 0`'d on the first failure, skipping the hook-wiring
110
+ step — so the SessionStart hook (which can itself re-clone) was never registered and
111
+ nothing ever recovered. Now the clone retries with backoff (5 attempts), and if it
112
+ still fails the script persists a copy of itself and wires a SessionStart **recovery
113
+ hook** that re-runs the bootstrap next session (egress is up by then); the first
114
+ successful run merges the private-sync hooks and removes the recovery hook.
115
+ - fix: `tools/cloud-setup.sh` also wires that recovery hook when
116
+ `DOTAGENTS_AGENTS_REMOTE` is **unset at setup time**, not only on clone failure.
117
+ Hosted runners often expose the remote/token secrets to session processes but not
118
+ to the setup-script phase, so the first bootstrap had no remote to clone and its
119
+ no-remote branch just `exit 0`'d, leaving nothing to retry — the environment stayed
120
+ dead every session (observed: setup ran the correct one-liner and emitted only the
121
+ banner + `skipping` line, ~154 bytes, no clone). The branch now persists the recovery
122
+ hook like the exhausted-clone path, so the next session — where the secret is present
123
+ — clones and self-removes the hook. A genuinely remote-less environment just re-skips
124
+ each session (idempotent; the hook never duplicates). (Durable fix is still
125
+ to expose the secrets to the Setup Script phase so the first container succeeds.)
126
+ - fix: `.gitignore` templates and `dotagents link` now use a slashless `.agents`
127
+ instead of `.agents/`. `link` creates `.agents` as a *symlink*, which git treats
128
+ as a file, so the directory-only `.agents/` pattern never actually ignored it —
129
+ the link showed up as untracked in every project. `_gitignore_excludes_agents`
130
+ is now symlink-aware (a bare `.agents/` no longer counts as excluding a symlinked
131
+ link, so the WARN fires), and the reference template, REPO.md guidance, and the
132
+ starter `_overlay/AGENTS.md` Leakage rule all recommend `.agents`.
133
+ - docs: recommend `curl … -o file && sh file` over `curl … | sh` for the setup-script
134
+ field (README, `kb/PRIVATE_SYNC.md`, `tools/cloud-setup.sh` header). With a pipe the
135
+ field's exit code is `sh`'s (0 on empty stdin), so a failed fetch at container start
136
+ is silently reported as success; `&&` propagates the fetch failure to the setup log.
137
+
138
+ ### Changed
139
+
140
+ - refactor: move the cloud bootstrap from `overlays/private-sync/hooks/cloud-setup.sh` to
141
+ top-level `tools/cloud-setup.sh` (public, required tooling) so a fresh cloud container
142
+ can fetch-and-run it from the public repo instead of pasting its contents — the web
143
+ environment setup-script field becomes a one-liner
144
+ (`curl -fsSL …/tools/cloud-setup.sh | sh`) that stays current on every container start.
145
+ Docs (README, `kb/PRIVATE_SYNC.md`) updated to the download bootstrap.
146
+ - fix: `tools/cloud-setup.sh` prints `starting`/`done` banners (so a setup-script log
147
+ proves whether it executed — a blank log means the field never invoked it, a config
148
+ issue) and `mkdir -p "$HOME"` before `git config --global` (which fails if HOME isn't
149
+ created yet in some setup contexts).
150
+
151
+ ## [0.2.0] - 2026-07-19
152
+
153
+ ### Changed
154
+
155
+ - chore: migrate the CLI to `duho>=0.3.3` (was `>=0.1.1`). duho's Plan-13 `Args`/`Cmd`
156
+ split means commands are now `class X(LoggingArgs, Cmd)` with a `__call__` entrypoint
157
+ (was a bare `LoggingArgs` with `__run__`) and the umbrella root is
158
+ `class Dotagents(LoggingArgs, Cli)`. Field declarations (annotation + help string +
159
+ flags tuple) are unchanged. Bumped the `build-pyz` vendored `duho` default to 0.3.3.
160
+ - fix: restore full flag/help fidelity in the built `dotagents.pyz` under duho 0.3.3.
161
+ duho discovers each field's flags + help by AST-parsing its module source, and inside
162
+ a zipapp the zip-internal `__file__` isn't readable — degrading `--from` to `--from-`,
163
+ the `link` positional to `--path`, and dropping help text. `cli.main` now repoints the
164
+ affected module sources (`dotagents.cli`, `duho.presets`) to extracted temp files
165
+ before dispatch; a no-op for a plain install.
166
+
167
+ ### Added
168
+
169
+ - feat: private-agents git sync — `dotagents link` symlinks a project's `.agents` to a
170
+ per-project store under the global `~/.agents/projects/<name>` (basename-keyed, so a
171
+ local and a cloud checkout converge on the same store), adopting an existing real
172
+ `.agents/` into an empty store on the first link; `--copy` mirrors it as a real dir
173
+ for no-symlink environments (with automatic fallback), `--force` handles conflicts.
174
+ `dotagents sync` runs `git pull --rebase`/commit/push on the private repo, copies a
175
+ copy-mode project's `.agents` back into its store first (`--project`), and bootstraps
176
+ a fresh repo in one command (`--remote`). Logic in `src/dotagents/_link.py`; the model
177
+ keeps per-user config and every project's private `.agents` in one private repo while
178
+ the public project repos track none of it (the Leakage rule already `.gitignore`s
179
+ `.agents/`).
180
+ - feat: `overlays/private-sync/` overlay — `kb/PRIVATE_SYNC.md` (the model, commands,
181
+ first-time + cloud setup, auth, gotchas) plus `hooks/private-sync-{start,stop}.sh`
182
+ (SessionStart clone/pull + link, Stop sync-back) and a `settings.snippet.json` for
183
+ `~/.claude/settings.json`, so cloud sessions link and sync automatically. Cloud auth is
184
+ a fine-grained PAT via `DOTAGENTS_AGENTS_TOKEN`, wired through a git credential helper
185
+ that reads it from the environment (never persisted to `.git/config`);
186
+ `hooks/_agents-git-auth.sh` auto-detects a hosted-runner `github.com`→in-session-proxy
187
+ `insteadOf` rewrite and bypasses it (isolated git config) so token auth reaches the
188
+ real github.com for a private repo outside the session's scope. `hooks/cloud-setup.sh`
189
+ is a self-contained container-start bootstrap (inlines auth + bypass, so it runs before
190
+ `~/.agents` exists) that clones/pulls the repo, installs the CLI, and links the project
191
+ — for the web environment's setup-script field, solving the first-clone chicken-and-egg
192
+ the SessionStart hook can't.
193
+ - feat: installable `dotagents` CLI package (`src/dotagents/`, built on `duho` for
194
+ the argument surface and `pathlib_next` for copy/URI handling) exposing `init`
195
+ (lay down the neutral base overlay), `install` (base plus opt-in overlays via
196
+ repeatable `--overlays <path>`, copied additively), `audit` (wraps
197
+ `tools/audit_config.py`), and `build-pyz` (vendors pinned `duho`/`pathlib_next`
198
+ via `pip install --target` + `zipapp` into a self-contained, downloadable
199
+ `dotagents.pyz`). `init`'s `AGENTS.md`/`CLAUDE.md` are merged as a
200
+ marker-delimited managed block so re-running never clobbers customizations
201
+ outside the block. `install --bin-dir` writes `dotagents`/`dotagents.cmd`
202
+ wrappers. `install.py` is a thin shim over `dotagents.cli.main()`.
203
+ - Config content is a **neutral base overlay** (`src/dotagents/_overlay/` — the
204
+ `AGENTS.md` scaffolding + design-log convention `init` writes) plus **opt-in
205
+ overlays** (`overlays/<name>/`): `flows` (PLAN/EXEC/REVIEW/REPO + MODELS),
206
+ `recovery`, `references`, `python`/`node`/`rust`, `agents`, `tools`. Each carries
207
+ an `overlay.toml` manifest for a future `dotagents overlays` subcommand.
208
+ - Repo layout: the CLI in `src/dotagents/`, config overlays in `overlays/`, required
209
+ tooling in top-level `tools/` (`audit_config.py`, `leak_check.py`); repo root holds
210
+ the installer, CI, repo-development directives, and the tracked, sanitized
211
+ `.agents/` design log (index + per-decision files) + plans. `audit_config.py` has
212
+ `--repo-hygiene` (scans tracked files for personal/machine-specific leftovers).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jose A.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,291 @@
1
+ Metadata-Version: 2.4
2
+ Name: dotagents-cli
3
+ Version: 0.3.0
4
+ Summary: The dotagents CLI: install and manage a portable ~/.agents config for AI coding agents
5
+ Project-URL: Homepage, https://github.com/jose-pr/dotagents/
6
+ Project-URL: Repository, https://github.com/jose-pr/dotagents
7
+ Project-URL: Documentation, https://jose-pr.github.io/dotagents/
8
+ Author: Jose A.
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 Jose A.
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Classifier: Development Status :: 4 - Beta
32
+ Classifier: Environment :: Console
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Operating System :: OS Independent
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.9
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Programming Language :: Python :: 3.13
42
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
43
+ Requires-Python: >=3.9
44
+ Requires-Dist: duho>=0.4.0
45
+ Requires-Dist: pathlib-next>=0.8.0
46
+ Provides-Extra: dev
47
+ Requires-Dist: pytest; extra == 'dev'
48
+ Provides-Extra: docs
49
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
50
+ Requires-Dist: mkdocs>=1.5; extra == 'docs'
51
+ Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
52
+ Provides-Extra: http
53
+ Requires-Dist: pathlib-next[http]; extra == 'http'
54
+ Provides-Extra: s3
55
+ Requires-Dist: pathlib-next[s3]; extra == 's3'
56
+ Provides-Extra: sftp
57
+ Requires-Dist: pathlib-next[sftp]; extra == 'sftp'
58
+ Provides-Extra: uri
59
+ Requires-Dist: pathlib-next[uri]; extra == 'uri'
60
+ Description-Content-Type: text/markdown
61
+
62
+ # dotagents
63
+
64
+ [![Test](https://img.shields.io/github/actions/workflow/status/jose-pr/dotagents/test.yml?branch=main&label=tests)](https://github.com/jose-pr/dotagents/actions/workflows/test.yml)
65
+ [![Documentation](https://img.shields.io/badge/docs-online-blue.svg)](https://jose-pr.github.io/dotagents/)
66
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/jose-pr/dotagents/blob/main/LICENSE)
67
+
68
+ Like dotfiles, but for AI coding agents: a portable, token-budgeted `~/.agents`
69
+ configuration that works across agent runners (Claude Code, Antigravity, Copilot,
70
+ Codex, ...). dotagents is the **mechanism** — install a neutral base, then layer in
71
+ opt-in **overlays** that carry your standards (repo structure, CI/release discipline,
72
+ whatever workflows you want) — so you record them once instead of restating them every
73
+ session.
74
+
75
+ ## Design
76
+
77
+ - **Core + load-on-demand routing.** `AGENTS.md` is the only always-loaded file: a
78
+ handful of always-on rules plus a routing table. Task-specific detail lives in
79
+ `flows/` and `kb/` files that an agent reads only when the task matches. You pay for
80
+ what you use.
81
+ - **A neutral base + opt-in overlays.** `init` lays down a minimal, opinion-free
82
+ **base overlay** (just the `AGENTS.md` scaffolding + design-log convention).
83
+ Everything opinionated — workflows, language `kb/` files, repo templates, tools —
84
+ lives in composable **overlays** you layer in explicitly
85
+ (`dotagents overlays add <name>`), each contributing its own routing lines, rules,
86
+ skills, and commands. Additive-only: overlays never overwrite something you've
87
+ already customized.
88
+ - **Overlays carry the opinions, not the tool.** dotagents is the mechanism
89
+ (install, compose, discover); *what* your agents should do is an overlay concern.
90
+ The example overlays in this repo are a starting point — a planning/execution/review
91
+ workflow set, language conventions, a release helper — but they're payloads riding on
92
+ dotagents, swappable for your own. See the [docs](https://jose-pr.github.io/dotagents/)
93
+ for what each ships.
94
+
95
+ ## Layout
96
+
97
+ The config is a **base overlay** plus opt-in **overlays**; the `dotagents` CLI applies
98
+ them. Everything else is repo infrastructure.
99
+
100
+ | Path | What |
101
+ | --- | --- |
102
+ | `src/dotagents/` | The installable `dotagents` CLI (`init`/`overlays`/`context`/`env`/`build-pyz`) — that is the whole shipped surface; commands beyond it come from overlays or your own `cmds/` modules |
103
+ | `src/dotagents/_overlay/` | The **base overlay** `init` writes: `AGENTS.md` scaffolding, `CLAUDE.md`, `dotagents/DECISIONS.md` (empty design-log index), and an empty `dotagents/cmds/` dir — your drop-in point for your own command modules. Neutral — imposes no flows, ships no command |
104
+ | `tools/` | Required tooling (not an overlay): `cloud-setup.sh` (`leak-check` moved to the opt-in `leak-check` overlay, D84) |
105
+ | `install.py` | Thin shim over `dotagents.cli.main()`, kept at this filename for muscle memory |
106
+
107
+ The **example overlays** — the `flows` workflow set, per-language `kb/` + templates,
108
+ `references`, `release`, `private-sync`, `net`, `recovery`, `tools` — live on a separate
109
+ [`overlays` branch](https://github.com/jose-pr/dotagents/tree/overlays), not in `main`'s
110
+ tree: they are swappable payloads, not part of the tool. `dotagents overlays add <name>`
111
+ resolves them from there (or from any `--source`). See the
112
+ [docs](https://jose-pr.github.io/dotagents/) for what each ships.
113
+
114
+ Named-agent directives aren't a shipped overlay — a named agent (Claude, Antigravity,
115
+ …) just reads its own `~/.agents/<agent>.md` on top of the shared `AGENTS.md`, which the
116
+ base overlay's routing already states. This config's own design log lives **privately**
117
+ under its untracked `.agents/dotagents/` (`DECISIONS.md` + one file per decision) — like
118
+ every project, `.agents/` is never tracked or pushed.
119
+
120
+ Each overlay's `<name>/overlay.toml` carries a `name`/`description`/`requires`/`routing`
121
+ manifest read by the `dotagents overlays` subcommand, which manages overlays by name
122
+ (`add`/`remove`/`list`/`sync`) — see [Managing overlays](#managing-overlays) below.
123
+
124
+ ## Install
125
+
126
+ **`dotagents init`** lays down the neutral base config; a self-contained downloadable
127
+ `.pyz` needs no `pip install` at all.
128
+
129
+ `init` writes the `.agents/` scaffolding — the `AGENTS.md` managed block, the per-agent
130
+ `<CLAUDE|ANTIGRAVITY|...>.md → @AGENTS.md` pattern, the design-log convention — and
131
+ wires each supporting agent's hooks so `dotagents context` reaches it automatically at
132
+ session start (`--no-hooks` opts out) — but
133
+ imposes no opinions (those come from `overlays add`). Its `AGENTS.md`/`CLAUDE.md` are a
134
+ marker-delimited managed block, so re-running `init` never clobbers what you've added
135
+ around it. **Scope**: project by default (`<cwd>/.agents`), or the user store with
136
+ `-g`/`--global` (`~/.agents`).
137
+
138
+ ```bash
139
+ dotagents init # project: <cwd>/.agents
140
+ dotagents init -g # user store: ~/.agents
141
+ dotagents init --bin-dir ~/.local/bin # also write a `dotagents` command on PATH
142
+ dotagents init --dry-run # show what would happen
143
+ dotagents init --force # replace AGENTS.md/CLAUDE.md wholesale (backed up)
144
+ ```
145
+
146
+ `--from <path-or-uri>` selects the *base* source for a `pip install`-only environment
147
+ (a git checkout dir, `file:`, `http(s):`, `zip:`, `sftp:`, or `s3:` URI via
148
+ `pip install "dotagents-cli[uri]"`); `init`'s base ships inside the package, so it needs no
149
+ `--from`.
150
+
151
+ Overlays beyond the base are managed by name with `dotagents overlays add <name>` — it
152
+ installs into `<scope>/.agents/overlays/<name>/` (discoverable) and publishes the
153
+ overlay's skills into the shared skills dir. See below.
154
+
155
+ ### Managing overlays
156
+
157
+ `dotagents overlays` manages opt-in overlays **by name**, resolving each name against a
158
+ source directory of overlays — point `--source <dir>` (or `$AGENTS_OVERLAYS_SRC`) at
159
+ one, e.g. a checkout of the [`overlays` branch](https://github.com/jose-pr/dotagents/tree/overlays)
160
+ where the example overlays live. Installed overlays are *discovered* by their presence
161
+ under `<scope>/.agents/overlays/` — there is no registry file.
162
+
163
+ ```bash
164
+ dotagents overlays add python flows # install into the scope, publish skills, merge D59 rules/routing
165
+ dotagents overlays list # installed (discovered) + available (from source)
166
+ dotagents overlays sync 'py*' # refresh installed overlays matching a glob, resync their skills
167
+ dotagents overlays remove python # delete the overlay dir + unpublish its skills
168
+ ```
169
+
170
+ Scope is **project** by default (`<project>/.agents/`, when run inside one) or **user**
171
+ with `-g`/`--global` (`~/.agents/`, the configurable store). Each overlay installs as a
172
+ directory (kept, discoverable), its `routing`/`rules` merge additively into `AGENTS.md`'s
173
+ managed block, and its `skills/<name>/` are symlinked (or `--copy`'d, for Windows /
174
+ no-symlink) into the shared `<scope>/.agents/skills/` so every agent sees the same skills.
175
+ `add`/`sync` are additive and never clobber a file you hand-edited inside an installed
176
+ overlay. Removing an overlay deletes only its dir and unpublishes only the skills **it**
177
+ published; its lines in `AGENTS.md`'s managed block are not auto-pruned (a warning points
178
+ at the manual edit, or re-run `install`).
179
+
180
+ **Overlay setup scripts.** An overlay may ship an **idempotent** `setup.py` at its root
181
+ (the recommended form: it runs under the same Python that runs dotagents, so it works on
182
+ every OS — the bundled `net` overlay is the model). An extensionless `setup` (a POSIX
183
+ shell script) is still honored as a legacy fallback, but it is discouraged: a shell
184
+ script isn't portable to Windows without a shell. After `add`/`sync` copies the overlay
185
+ in, dotagents runs the script automatically — so anything a human would otherwise
186
+ hand-follow (PATH/lib wiring, self-registration) is one script the tool runs, not a doc.
187
+ When both are present, `setup.py` wins. Presence of a script is the opt-in; skip it with
188
+ `--no-setup`. The contract for authors:
189
+
190
+ - **Idempotent** — safe to run on every `add`/`sync`; check-then-act, never blindly append.
191
+ - **cwd** is the installed overlay dir (`<scope>/.agents/overlays/<name>/`), so reference
192
+ your own files by relative path.
193
+ - **Env** carries `AGENTS_HOME` (the resolved store path — never hardcode
194
+ `~/.agents`) and `AGENTS_OVERLAY_DIR` (your own installed dir).
195
+ - A **non-zero exit fails the install** with a clear error (not a silent skip). For any
196
+ outward or irreversible action the *script* must confirm first — the runner invokes a
197
+ script you chose to install; it does not second-guess it.
198
+
199
+ **Downloadable `dotagents.pyz`** — a self-contained zipapp with `duho`/
200
+ `pathlib_next` and the required `tools/` bundled in, so it needs no `pip install`:
201
+
202
+ ```bash
203
+ python -m dotagents build-pyz --out dist/dotagents.pyz # build it (needs this repo checkout)
204
+ python dist/dotagents.pyz init --bin-dir ~/.local/bin # lay down the base + a `dotagents` command, offline
205
+ ```
206
+
207
+ Then wire your runner to it — e.g. Claude Code: put `@AGENTS.md` in
208
+ `~/.claude/CLAUDE.md`... which is exactly what the installed `CLAUDE.md` contains.
209
+
210
+ **Or let your agent do it:** point it at this repo and say —
211
+ > Read README.md, run `python install.py init && python install.py overlays add flows -g`,
212
+ > and confirm `~/.agents/overlays/flows/flows/PLAN.md` exists.
213
+
214
+ ## Private sync (per-user + per-project, one private repo)
215
+
216
+ Keep your global config **and** every project's private `.agents` (plans, kb, findings)
217
+ in a single private git repo — synced across machines and cloud sessions — without ever
218
+ committing any of it into the (often public) project repos.
219
+
220
+ The idea: your global `~/.agents` **is** a private git repo. Its root is the per-user
221
+ config; a `projects/<name>/` tree holds each project's private `.agents` payload. For a
222
+ checked-out project, `<project>/.agents` is a **symlink** to `~/.agents/projects/<name>`
223
+ (the project's `.gitignore` already excludes `.agents/` per the Leakage rule, so the
224
+ link never lands in the public repo). `<name>` defaults to the project's basename, so a
225
+ local `~/code/app` and a cloud `/home/user/app` resolve to the same store.
226
+
227
+ The `link-project` / `sync-project` commands are **supplied by the `private-sync`
228
+ overlay**, not by dotagents itself — installing the overlay is what makes them exist
229
+ (it ships the commands, their logic, the `kb/` walkthrough and the cloud hooks
230
+ together). So `overlays add private-sync` comes first:
231
+
232
+ ```bash
233
+ dotagents init # base
234
+ dotagents overlays add private-sync --source <overlays-checkout> # commands + kb + hooks
235
+ dotagents link-project . # symlink this project's .agents into the private repo
236
+ # (an existing .agents/ is adopted in on the first link;
237
+ # --copy mirrors it as a real dir for no-symlink systems)
238
+ dotagents sync-project -m msg # git pull --rebase / commit / push the private repo
239
+ dotagents sync-project --remote git@github.com:<you>/.agents.git -m init # one-command bootstrap
240
+ ```
241
+
242
+ In cloud sessions, the installed `~/.agents/hooks/private-sync-{start,stop}.sh` clone/pull
243
+ the private repo and link/sync the project per session — register them in
244
+ `~/.claude/settings.json` (see `~/.agents/hooks/settings.snippet.json`). For a **fresh
245
+ container** (no `~/.agents` yet), point the web environment's **setup-script** field at the
246
+ self-contained bootstrap in this repo — it fetches the latest each start, so there's
247
+ nothing to re-paste:
248
+
249
+ ```bash
250
+ curl -fsSL https://raw.githubusercontent.com/<you>/dotagents/main/tools/cloud-setup.sh -o /tmp/dg-cloud-setup.sh && sh /tmp/dg-cloud-setup.sh
251
+ ```
252
+
253
+ Use `curl … -o file && sh file`, not `curl … | sh`: with a pipe the setup field's exit
254
+ code is `sh`'s (0 on empty stdin), so a failed fetch is silently logged as success; `&&`
255
+ propagates the curl failure instead.
256
+
257
+ It authenticates (bypassing a hosted-runner `github.com`→proxy git rewrite), clones/pulls
258
+ `~/.agents`, installs the CLI, and links the project — driven by `AGENTS_REMOTE`
259
+ / `DOTAGENTS_AGENTS_TOKEN` / `DOTAGENTS_CLI_INSTALL` env vars (token never committed). Full
260
+ walkthrough: `~/.agents/kb/PRIVATE_SYNC.md`.
261
+
262
+ ## Validate
263
+
264
+ ```bash
265
+ python tools/audit.py --root . # validate THIS REPO's layout (CI tooling)
266
+ python tools/audit.py --check-templates --root . # + template checks (needs 3.11+)
267
+ ```
268
+
269
+ ## Customize
270
+
271
+ Fork it — that's the point. Keep the base `AGENTS.md` small (the audit warns past
272
+ ~2.5KB); put opinionated content in overlays. Your `~/.agents/dotagents/DECISIONS.md`
273
+ is *your* private, per-install design log (index + `decisions/` files) — installed
274
+ empty, edited directly, never distributed. This repo follows the same rule: its own
275
+ design log and all working material live in an **untracked** `.agents/dotagents/`, never
276
+ committed — so what's public here is only the CLI, the base overlay, and the opt-in
277
+ overlays. If you fork, keep the tracked surface free of personal paths and private
278
+ project names. `dotagents audit` validates config *structure* only; personal-leak
279
+ scanning (machine paths, private plan names, session trailers) is a separate,
280
+ personal `leak-check` tool you run locally before a push — it lives in your private
281
+ `.agents/`, not shipped in this repo.
282
+
283
+ ## Documentation
284
+
285
+ Full docs — install modes, the overlay model, the CLI command surface, private sync,
286
+ authoring your own overlays and commands, and the API reference — are at
287
+ [jose-pr.github.io/dotagents](https://jose-pr.github.io/dotagents/).
288
+
289
+ ## License
290
+
291
+ MIT — see [LICENSE](LICENSE).