Scope
dotagents._scope
Scope and overlay-source resolution for dotagents overlays.
Two orthogonal axes the overlays command needs, kept out of cli.py (which
only wires args) to match _overlays.py / _skills.py / _sync.py:
-
Scope -- where installed overlays live.
useris<agents_dir>/(the configurable store, default~/.agents);projectis<project>/.agents/. An overlay installs into<scope>/overlays/<name>/and skills publish into the shared<scope>/skills/. There is no registry file: installed overlays are discovered by their presence underoverlays/(the locked "discover, don't track" decision). Asystemtier (/etc/agents) is designed-for but not built. -
Source -- where an overlay to install comes from.
resolve_sourcereturns anOverlaySourcewhose.rootis a local directory of<name>/overlay dirs. The default is the bundledoverlays/(resolved.pyz-safe viaimportlib.resources, mirroringcli._package_data_dir); an explicit--source/$AGENTS_OVERLAYS_SRCoverrides it. A git/URI source is a later swap of the resolver's default --resolve_sourceis the single extension point (clone/pull into a cache, then hand back a local.root), so a repo source drops in with no change to the command classes.
Never print DOTAGENTS_* values (Leakage): this module reads the env var but
only ever reports the resolved path, never the raw value.
SOURCE_ENV = 'AGENTS_OVERLAYS_SRC'
module-attribute
SOURCE_ENV_LEGACY = 'DOTAGENTS_OVERLAYS_SRC'
module-attribute
OverlaySource(root)
A resolved place overlays are fetched from for add/sync.
root is a local directory holding <name>/ overlay dirs. available()
lists them; overlay_dir(name) resolves one (raising if absent). This is the
seam a future git/URI source slots into: a GitOverlaySource would clone/pull
into a cache in __init__ and set root to that checkout -- the command
classes only ever touch this interface, so they need no change.
Source code in src/dotagents/_scope.py
180 181 | |
root = Path(root)
instance-attribute
__repr__()
Source code in src/dotagents/_scope.py
201 202 | |
available()
Source code in src/dotagents/_scope.py
183 184 185 186 187 188 189 190 | |
overlay_dir(name)
Source code in src/dotagents/_scope.py
192 193 194 195 196 197 198 199 | |
Scope(level, agents_root)
A resolved install scope: the roots overlays and skills live under.
user -> <agents_dir>/ (the configurable store, default ~/.agents).
project -> <project_root>/.agents/. The overlays/ and skills/
subdirs beneath agents_root are the discover-and-publish surfaces.
Source code in src/dotagents/_scope.py
68 69 70 | |
agents_root = Path(agents_root)
instance-attribute
cmds_dir
property
Directory of discovered command modules for this scope (D76).
<agents_root>/dotagents/cmds -- a seam alongside overlays/skills.
init/install lay the bundled command modules here, and
dotagents.cli._discover runs duho.discover_commands over it (per
scope, user + project) so a user's own *.py command modules dropped
beside them are picked up with zero config.
level = level
instance-attribute
overlay_root
property
shared_skills_dir
property
__repr__()
Source code in src/dotagents/_scope.py
94 95 | |
overlay_dir(name)
Source code in src/dotagents/_scope.py
91 92 | |
bundled_overlays_root()
Locate the bundled example overlays/ directory, .pyz-safe.
Two homes, tried in order: the packaged copy (importlib.resources under the
installed dotagents package -- extracted from a zipapp when needed, exactly
like cli._package_data_dir), then a repo checkout's top-level overlays/
(dev use, mirroring BuildPyz's parents[2] reach). Returns None if
neither exists -- a plain pip install that bundled no overlays.
Source code in src/dotagents/_scope.py
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | |
discover_overlays(scope)
Installed overlay names in this scope -- the presence of overlays/<name>/.
No registry: a directory under <scope>/overlays/ is an installed overlay
(manifest or not) as long as its name is a valid overlay name
(:func:is_valid_overlay_name -- so .git/__pycache__/dotfiles are
skipped). Returns sorted names; empty if the root is absent.
Source code in src/dotagents/_scope.py
147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
filter_names(names, pattern)
Glob-filter overlay names (sync 'py*'). None/'*' keep all.
Source code in src/dotagents/_scope.py
163 164 165 166 167 | |
is_valid_overlay_name(name)
A dir under overlays/ is an overlay iff its name matches: a leading ASCII
letter, then ASCII letters/digits/_/./-. Dots are allowed mid-name
(foo.bar, v1.2) but NOT as the first char, so .git/.hidden and
__pycache__ (leading _) and 2fast (leading digit) are excluded.
Source code in src/dotagents/_scope.py
45 46 47 48 49 50 | |
normalize_overlay_name(name)
Overlay names normalize to lowercase-dash for matching (precursor rule):
name.lower().replace('_', '-'). So My_Overlay and my-overlay are
the same overlay.
Source code in src/dotagents/_scope.py
53 54 55 56 57 | |
project_root_default()
The project root when none is passed explicitly, in precedence order:
$AGENTS_PROJECT_ROOT (dotagents' canonical var) -> a known agent-native var
(:data:_HARNESS_PROJECT_ROOT_VARS, e.g. Claude Code's CLAUDE_PROJECT_DIR)
-> the current working directory.
Emitting AGENTS_PROJECT_ROOT (see dotagents env) lets every command and
subprocess agree on one root regardless of the cwd it happens to run in.
Source code in src/dotagents/_scope.py
132 133 134 135 136 137 138 139 140 141 142 143 144 | |
resolve_scope(global_scope=False, *, agents_dir=None, project_root=None)
Pick the install scope.
-g/--global forces the user scope (agents_dir, default ~/.agents).
Otherwise the scope is project, rooted at (in precedence order): an explicit
project_root argument, else $AGENTS_PROJECT_ROOT if set, else the current
directory. $AGENTS_PROJECT_ROOT lets a harness (or dotagents env) pin the
project root once so every command agrees on it regardless of the cwd a subprocess
happens to run in; <root>/.agents/ is where this project's overlays live. The
store location is configurable (D58): agents_dir comes from the caller
(--agents-dir) or defaults to ~/.agents; never hardcoded past that default.
Source code in src/dotagents/_scope.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
resolve_source(source=None)
Resolve the overlay source: explicit --source / $AGENTS_OVERLAYS_SRC,
else the bundled overlays/.
Today every branch yields a local directory OverlaySource. The single
extension point for a git/URI source is here: when raw looks like a URI (a
later change), construct a GitOverlaySource instead -- callers are unaffected
because they only use the returned object's available/overlay_dir.
Source code in src/dotagents/_scope.py
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | |