agent-usage-manager 0.2.5__tar.gz → 0.2.6__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 (28) hide show
  1. agent_usage_manager-0.2.5/README.md → agent_usage_manager-0.2.6/PKG-INFO +53 -3
  2. agent_usage_manager-0.2.5/PKG-INFO → agent_usage_manager-0.2.6/README.md +18 -22
  3. agent_usage_manager-0.2.5/agent_usage_manager/agents.yaml → agent_usage_manager-0.2.6/agent_usage_manager/agents.default.yaml +38 -50
  4. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/agent_usage_manager/app.py +16 -6
  5. agent_usage_manager-0.2.6/pyproject.toml +55 -0
  6. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/tests/test_design_docs.py +5 -6
  7. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/uv.lock +1 -1
  8. agent_usage_manager-0.2.5/pyproject.toml +0 -31
  9. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/.github/workflows/ci.yml +0 -0
  10. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/.github/workflows/publish.yml +0 -0
  11. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/.gitignore +0 -0
  12. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/AGENTS.md +0 -0
  13. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/CLAUDE.md +0 -0
  14. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/LICENSE +0 -0
  15. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/agent_usage_manager/__init__.py +0 -0
  16. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/agent_usage_manager/cli.py +0 -0
  17. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/agent_usage_manager/static/index.html +0 -0
  18. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/demo.tape +0 -0
  19. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/docs/dashboard-live.gif +0 -0
  20. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/docs/dashboard-live.png +0 -0
  21. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/docs/dashboard.png +0 -0
  22. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/docs/demo.gif +0 -0
  23. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/docs/design/HLD.md +0 -0
  24. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/docs/design/LLD.md +0 -0
  25. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/requirements.txt +0 -0
  26. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/run.sh +0 -0
  27. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/tests/test_smoke.py +0 -0
  28. {agent_usage_manager-0.2.5 → agent_usage_manager-0.2.6}/tests/test_synthetic.py +0 -0
@@ -1,17 +1,52 @@
1
+ Metadata-Version: 2.5
2
+ Name: agent-usage-manager
3
+ Version: 0.2.6
4
+ Summary: htop for AI agents — liveness, CPU/mem/GPU usage, and a kill switch for headless agents (openclaw, hermes, ollama, vllm, claude-code).
5
+ Project-URL: Homepage, https://github.com/minglong51/agent-usage-manager
6
+ Project-URL: Repository, https://github.com/minglong51/agent-usage-manager
7
+ Project-URL: Issues, https://github.com/minglong51/agent-usage-manager/issues
8
+ Project-URL: Newsletter, https://buttondown.com/minglong51
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai-agents,gpu,llm,monitoring,observability,ollama,vllm
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Web Environment
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: MacOS :: MacOS X
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: System :: Monitoring
25
+ Classifier: Topic :: System :: Systems Administration
26
+ Requires-Python: >=3.9
27
+ Requires-Dist: fastapi>=0.110
28
+ Requires-Dist: psutil>=5.9
29
+ Requires-Dist: pyyaml>=6.0
30
+ Requires-Dist: uvicorn[standard]>=0.27
31
+ Provides-Extra: dev
32
+ Requires-Dist: httpx>=0.27; extra == 'dev'
33
+ Requires-Dist: pytest>=7; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
1
36
  # agent-usage-manager
2
37
 
3
38
  A small web dashboard for **headless AI agents** running on a machine —
4
39
  OpenClaw, Hermes, Claude Code, Ollama, vLLM, llama.cpp, or anything you name. It
5
40
  shows which agents are alive and what they're costing you (CPU, memory, GPU), and
6
41
  gives you a **kill button** per agent. Think `htop`, scoped to just your agents —
7
- the [screenshot below](docs/dashboard.png) is a real run on a fleet node.
42
+ the [screenshot below](https://raw.githubusercontent.com/minglong51/agent-usage-manager/main/docs/dashboard.png) is a real run on a fleet node.
8
43
 
9
44
  No database, no auth framework (one static token file gates the kill switch),
10
45
  four direct dependencies (FastAPI, uvicorn, psutil, PyYAML). Runs on macOS and Linux. It is a
11
46
  per-node monitor and guarded local control panel: fleet schedulers may consume
12
47
  its read-only telemetry, but should own their own scheduling and actuation.
13
48
 
14
- ![agent-usage-manager — live dashboard](docs/dashboard.png)
49
+ ![agent-usage-manager — live dashboard](https://raw.githubusercontent.com/minglong51/agent-usage-manager/main/docs/dashboard.png)
15
50
 
16
51
  *A real run: ten agents grouped by process tree (`+N` = children rolled up),
17
52
  per-agent CPU/memory/uptime, launchd-supervised jobs flagged, and a kill button
@@ -39,7 +74,10 @@ uvx agent-usage-manager # then open http://127.0.0.1:8765 (opens automatica
39
74
  One command — no install, no virtualenv, no leftovers. Other install options,
40
75
  config, and flags: [Install & run](#install--run).
41
76
 
42
- ![one command to a live dashboard](docs/demo.gif)
77
+ ![one command to a live dashboard](https://raw.githubusercontent.com/minglong51/agent-usage-manager/main/docs/demo.gif)
78
+
79
+ *Field notes on running agents with discipline go out on the
80
+ [Agent Discipline](https://buttondown.com/minglong51) list — a few emails a month.*
43
81
 
44
82
  ## What it does
45
83
 
@@ -179,6 +217,18 @@ This is the important part — a web page that can kill processes needs guardrai
179
217
  actions. That is deliberate (owner-only tailnet + token-gated actions), but do
180
218
  not read "loopback-only" as "not network-reachable" — a proxy in front is not
181
219
  a trust boundary.
220
+ - **Fronting it with a proxy needs `AUM_TRUSTED_HOSTS`.** The DNS-rebinding guard
221
+ refuses any request whose `Host` is a non-local DNS name — which is exactly what
222
+ a proxy forwards. Opt that one name in explicitly:
223
+
224
+ ```bash
225
+ AUM_TRUSTED_HOSTS=box.your-tailnet.ts.net agent-usage-manager
226
+ ```
227
+
228
+ Comma-separated for several. Only add a name nobody else can mint a cert for on
229
+ this node; a name you don't control reopens the hole the guard exists to close.
230
+ Empty by default — out of the box only `localhost`, `127.0.0.1` and `::1` are
231
+ accepted.
182
232
 
183
233
  ## Limits & known issues
184
234
 
@@ -1,36 +1,17 @@
1
- Metadata-Version: 2.5
2
- Name: agent-usage-manager
3
- Version: 0.2.5
4
- Summary: htop for AI agents — liveness, CPU/mem/GPU usage, and a kill switch for headless agents (openclaw, hermes, ollama, vllm, claude-code).
5
- Project-URL: Homepage, https://github.com/minglong51/agent-usage-manager
6
- Project-URL: Repository, https://github.com/minglong51/agent-usage-manager
7
- License: MIT
8
- License-File: LICENSE
9
- Keywords: ai-agents,gpu,llm,monitoring,observability,ollama,vllm
10
- Requires-Python: >=3.9
11
- Requires-Dist: fastapi>=0.110
12
- Requires-Dist: psutil>=5.9
13
- Requires-Dist: pyyaml>=6.0
14
- Requires-Dist: uvicorn[standard]>=0.27
15
- Provides-Extra: dev
16
- Requires-Dist: httpx>=0.27; extra == 'dev'
17
- Requires-Dist: pytest>=7; extra == 'dev'
18
- Description-Content-Type: text/markdown
19
-
20
1
  # agent-usage-manager
21
2
 
22
3
  A small web dashboard for **headless AI agents** running on a machine —
23
4
  OpenClaw, Hermes, Claude Code, Ollama, vLLM, llama.cpp, or anything you name. It
24
5
  shows which agents are alive and what they're costing you (CPU, memory, GPU), and
25
6
  gives you a **kill button** per agent. Think `htop`, scoped to just your agents —
26
- the [screenshot below](docs/dashboard.png) is a real run on a fleet node.
7
+ the [screenshot below](https://raw.githubusercontent.com/minglong51/agent-usage-manager/main/docs/dashboard.png) is a real run on a fleet node.
27
8
 
28
9
  No database, no auth framework (one static token file gates the kill switch),
29
10
  four direct dependencies (FastAPI, uvicorn, psutil, PyYAML). Runs on macOS and Linux. It is a
30
11
  per-node monitor and guarded local control panel: fleet schedulers may consume
31
12
  its read-only telemetry, but should own their own scheduling and actuation.
32
13
 
33
- ![agent-usage-manager — live dashboard](docs/dashboard.png)
14
+ ![agent-usage-manager — live dashboard](https://raw.githubusercontent.com/minglong51/agent-usage-manager/main/docs/dashboard.png)
34
15
 
35
16
  *A real run: ten agents grouped by process tree (`+N` = children rolled up),
36
17
  per-agent CPU/memory/uptime, launchd-supervised jobs flagged, and a kill button
@@ -58,7 +39,10 @@ uvx agent-usage-manager # then open http://127.0.0.1:8765 (opens automatica
58
39
  One command — no install, no virtualenv, no leftovers. Other install options,
59
40
  config, and flags: [Install & run](#install--run).
60
41
 
61
- ![one command to a live dashboard](docs/demo.gif)
42
+ ![one command to a live dashboard](https://raw.githubusercontent.com/minglong51/agent-usage-manager/main/docs/demo.gif)
43
+
44
+ *Field notes on running agents with discipline go out on the
45
+ [Agent Discipline](https://buttondown.com/minglong51) list — a few emails a month.*
62
46
 
63
47
  ## What it does
64
48
 
@@ -198,6 +182,18 @@ This is the important part — a web page that can kill processes needs guardrai
198
182
  actions. That is deliberate (owner-only tailnet + token-gated actions), but do
199
183
  not read "loopback-only" as "not network-reachable" — a proxy in front is not
200
184
  a trust boundary.
185
+ - **Fronting it with a proxy needs `AUM_TRUSTED_HOSTS`.** The DNS-rebinding guard
186
+ refuses any request whose `Host` is a non-local DNS name — which is exactly what
187
+ a proxy forwards. Opt that one name in explicitly:
188
+
189
+ ```bash
190
+ AUM_TRUSTED_HOSTS=box.your-tailnet.ts.net agent-usage-manager
191
+ ```
192
+
193
+ Comma-separated for several. Only add a name nobody else can mint a cert for on
194
+ this node; a name you don't control reopens the hole the guard exists to close.
195
+ Empty by default — out of the box only `localhost`, `127.0.0.1` and `::1` are
196
+ accepted.
201
197
 
202
198
  ## Limits & known issues
203
199
 
@@ -1,3 +1,8 @@
1
+ # Default configuration shipped with the package. It is used only when you have
2
+ # no agents.yaml of your own: `--config` wins, then ./agents.yaml in the current
3
+ # directory, then this file. Copy it somewhere and edit rather than editing it
4
+ # in place — a package upgrade replaces this file.
5
+ #
1
6
  # Which processes count as "agents". A process matches if the pattern hits its
2
7
  # executable name + first few arguments (case-insensitive substring or regex) —
3
8
  # NOT the entire command line, so a process that merely mentions an agent name
@@ -68,38 +73,35 @@ ignore:
68
73
 
69
74
  # Optional: per-instance labels from launchd job labels — the supervised-fleet
70
75
  # counterpart of tmux_labels below. Several LaunchAgents running the same
71
- # binary (e.g. ai.hermes.gateway, ai.hermes.gateway-frontdoor, …) all hit one
72
- # agents: entry and land as indistinguishable rows, and tmux never sees them.
73
- # When a matched root's own launchd job label matches this regex, the first
74
- # capture group (the whole label if no group) becomes the row label — churn
75
- # tracking, alert transitions, and /metrics all get per-instance identity.
76
- # tmux_labels wins when both apply. Empty/absent = off.
77
- launchd_labels: "^ai\\.hermes\\.(?:gateway-)?(.+)$" # → gateway, frontdoor, engineering_3
76
+ # binary all hit one agents: entry and land as indistinguishable rows, and tmux
77
+ # never sees them. When a matched root's own launchd job label matches this
78
+ # regex, the first capture group (the whole label if no group) becomes the row
79
+ # label — churn tracking, alert transitions, and /metrics all get per-instance
80
+ # identity. tmux_labels wins when both apply. Empty/absent = off.
81
+ #
82
+ # launchd_labels: "^com\\.example\\.worker-(.+)$" # → worker-1, worker-2
78
83
 
79
84
  # Optional: per-instance labels from tmux session names. A fleet of identical
80
- # agents (e.g. several claude-code bots, one per tmux session bot-*) all hit
81
- # one agents: entry above and land as N indistinguishable rows — their
82
- # cmdlines can't tell them apart, because matching deliberately sees only the
83
- # executable + first args. The tmux session each one runs in IS its identity:
84
- # when a matched root (or an ancestor) is a tmux pane whose session name
85
- # matches this regex, the row is labeled with the first capture group (the
86
- # whole session name if there is no group). Sessions that don't match keep
87
- # their agents: label, so incidental tmux use never renames rows.
88
- tmux_labels: "^bot-(.+)$" # session bot-coder_1 → row label coder_1
85
+ # agents (e.g. several claude-code bots, one per tmux session) all hit one
86
+ # agents: entry above and land as N indistinguishable rows — their cmdlines
87
+ # can't tell them apart, because matching deliberately sees only the executable
88
+ # + first args. The tmux session each one runs in IS its identity: when a
89
+ # matched root (or an ancestor) is a tmux pane whose session name matches this
90
+ # regex, the row is labeled with the first capture group (the whole session
91
+ # name if there is no group). Sessions that don't match keep their agents:
92
+ # label, so incidental tmux use never renames rows.
93
+ #
94
+ # tmux_labels: "^bot-(.+)$" # session bot-worker1 → row label worker1
89
95
 
90
- # Labels whose idle state is NORMAL — agents that wait for work (bots parked
91
- # on a Telegram poll, gateways waiting for requests). They get no "idle"
92
- # badge: badging the whole waiting fleet wallpapers the dashboard and trains
93
- # badge-blindness (12 of 22 rows wore "idle 10m+" before this existed). Same
94
- # reasoning as `idle` being opt-in for alerts below. Case-insensitive
96
+ # Labels whose idle state is NORMAL — agents that wait for work (bots parked on
97
+ # a chat poll, gateways waiting for requests). They get no "idle" badge: badging
98
+ # the whole waiting fleet wallpapers the dashboard and trains badge-blindness.
99
+ # Same reasoning as `idle` being opt-in for alerts below. Case-insensitive
95
100
  # substrings of the row label (incl. tmux-derived ones), like ignore:.
96
- idle_ok:
97
- - admin
98
- - coder # covers coder_1…coder_4
99
- - hermes # covers the launchd_labels-renamed rows too (gateway,
100
- # frontdoor, engineering_*) — suppression matches the BASE
101
- # matcher label as well as the instance label
102
- - codex
101
+ #
102
+ # idle_ok:
103
+ # - gateway
104
+ # - worker
103
105
 
104
106
  # GPU sampling: nvidia-smi is used automatically when present (Linux/NVIDIA).
105
107
  # On Apple Silicon there is no per-process GPU API, so the GPU column is blank.
@@ -113,29 +115,15 @@ idle_ok:
113
115
  # fleet of agents that wait for work, idle is the NORMAL state, and alerting on
114
116
  # it floods the channel every time the server restarts and re-learns the fleet.
115
117
  #
116
- # Example (desktop notification):
118
+ # Nothing is wired by default — uncomment and point it at your own channel, then
119
+ # prove it with `agent-usage-manager test-alert` before a real badge depends on
120
+ # it. Two things worth knowing before you turn `hot` on: for inference agents
121
+ # pegged CPU IS the job, and spawn-heavy agents look like churn while working.
122
+ #
117
123
  # alerts:
118
124
  # command: 'terminal-notifier -title agent-usage-manager -message "$AUM_MSG"'
119
125
  # cooldown: 600 # seconds, default 600
120
126
  # flags: [hot, churn, leak] # default; add idle only if you really want it
121
- #
122
- # Live wiring on this host: record to the attention feed, never ring
123
- # (2026-07-06, Ming: "most of them are noise"). First live day pushed two false
124
- # positives — "codex churn" during legitimate spawn work and "claude-code hot"
125
- # during a working session; for inference agents, pegged-CPU IS the job.
126
- # Badges stay live on the dashboard + machinery panel; the feed line rides the
127
- # next digest. Genuine breakage has louder, independent signals (mcp-autoheal
128
- # GAVE UP, cron-health, sync-bot liveness). `hot` dropped from alerting
129
- # entirely.
130
- # Ref discipline (2026-07-30): one stable ref per (agent, flag) + --upsert-open,
131
- # so a repeat firing UPDATES the single open card in place instead of stacking
132
- # one per cooldown expiry (nine churn cards in five days); the refreshed card
133
- # carries the latest cpu/mem/pid snapshot. fyi level = feed-only, riding the
134
- # digest exactly like the retired notify.py --feed-only wiring did.
135
- alerts:
136
- command: '"$HOME/workspace/founder-agent-os/bin/attention" add --level fyi --source usage-manager --title "$AUM_MSG" --body "$AUM_MSG" --ref "usage-manager:$AUM_LABEL:$AUM_FLAG" --upsert-open'
137
- cooldown: 7200 # 2 h per (agent, flag)
138
- flags: [churn, leak]
139
- leak_floor_mb: 1536 # bots legitimately ratchet RSS as session
140
- # context grows; only push leak alerts once
141
- # the absolute footprint is actually large
127
+ # leak_floor_mb: 1536 # only alert on leak once the absolute footprint
128
+ # # is large — long-running agents legitimately
129
+ # # ratchet RSS as their context grows
@@ -41,7 +41,10 @@ def _resolve_config() -> Path:
41
41
  cwd_cfg = Path.cwd() / "agents.yaml"
42
42
  if cwd_cfg.exists():
43
43
  return cwd_cfg
44
- return BASE / "agents.yaml"
44
+ local = BASE / "agents.yaml"
45
+ if local.exists():
46
+ return local
47
+ return BASE / "agents.default.yaml"
45
48
 
46
49
 
47
50
  CONFIG_PATH = _resolve_config()
@@ -688,11 +691,18 @@ async def _lifespan(_: FastAPI):
688
691
  app = FastAPI(title="agent-usage-manager", lifespan=_lifespan)
689
692
 
690
693
 
691
- # Loopback names are always local. The ts.net FQDN is the tailnet front door:
692
- # `tailscale serve --https=8448` proxies to this app and preserves the Host
693
- # header. Only tailscaled can mint that name/cert for this node, so allowing
694
- # it does not reopen the DNS-rebinding hole _host_allowed exists to close.
695
- _LOCAL_HOSTS = {"localhost", "127.0.0.1", "::1", "minglongs-mac-mini.tailab5be0.ts.net"}
694
+ # Loopback names are always local. Anything else must be opted in per install via
695
+ # AUM_TRUSTED_HOSTS (comma-separated hostnames) — typically the FQDN of a reverse
696
+ # proxy or tailnet front door that preserves the Host header, e.g.
697
+ # `tailscale serve --https=8448` fronting this app. Only add a name that nobody
698
+ # else can mint a cert for on this node; any other name reopens the DNS-rebinding
699
+ # hole _host_allowed exists to close.
700
+ def _configured_trusted_hosts() -> set[str]:
701
+ raw = os.environ.get("AUM_TRUSTED_HOSTS", "")
702
+ return {h.strip().lower() for h in raw.split(",") if h.strip()}
703
+
704
+
705
+ _LOCAL_HOSTS = {"localhost", "127.0.0.1", "::1"} | _configured_trusted_hosts()
696
706
 
697
707
 
698
708
  def _hostname_of(hostport: str) -> str:
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "agent-usage-manager"
7
+ version = "0.2.6"
8
+ description = "htop for AI agents — liveness, CPU/mem/GPU usage, and a kill switch for headless agents (openclaw, hermes, ollama, vllm, claude-code)."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.9"
12
+ keywords = ["ai-agents", "monitoring", "gpu", "ollama", "vllm", "llm", "observability"]
13
+ classifiers = [
14
+ "Development Status :: 4 - Beta",
15
+ "Environment :: Web Environment",
16
+ "Intended Audience :: Developers",
17
+ "Intended Audience :: System Administrators",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: MacOS :: MacOS X",
20
+ "Operating System :: POSIX :: Linux",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: System :: Monitoring",
27
+ "Topic :: System :: Systems Administration",
28
+ ]
29
+ dependencies = [
30
+ "fastapi>=0.110",
31
+ "uvicorn[standard]>=0.27",
32
+ "psutil>=5.9",
33
+ "pyyaml>=6.0",
34
+ ]
35
+
36
+ [project.optional-dependencies]
37
+ dev = ["pytest>=7", "httpx>=0.27"]
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/minglong51/agent-usage-manager"
41
+ Repository = "https://github.com/minglong51/agent-usage-manager"
42
+ Issues = "https://github.com/minglong51/agent-usage-manager/issues"
43
+ Newsletter = "https://buttondown.com/minglong51"
44
+
45
+ [project.scripts]
46
+ agent-usage-manager = "agent_usage_manager.cli:main"
47
+
48
+ [tool.hatch.build.targets.wheel]
49
+ packages = ["agent_usage_manager"]
50
+ # agents.yaml is the maintainer's live config in a source checkout, not a
51
+ # shippable default — the wheel carries agents.default.yaml instead.
52
+ exclude = ["agent_usage_manager/agents.yaml"]
53
+
54
+ [tool.hatch.build.targets.sdist]
55
+ exclude = ["agent_usage_manager/agents.yaml"]
@@ -17,6 +17,9 @@ context only.
17
17
 
18
18
  This file is shared verbatim across repos — it locates its own repo root, so it works
19
19
  at any depth. Do not fork it per repo.
20
+
21
+ Canonical home: ~/dotfiles/design-doc-contract/test_design_docs.py — patch there, then
22
+ propagate with ~/dotfiles/local-bin/design-doc-checker-sync.
20
23
  """
21
24
 
22
25
  import re
@@ -59,9 +62,7 @@ def contract_files() -> list[Path]:
59
62
 
60
63
  def contract_path() -> Path:
61
64
  """The contract file carrying the map. Prefers AGENTS.md when both have it."""
62
- candidates = [
63
- p for p in contract_files() if FENCE.search(p.read_text(encoding="utf-8"))
64
- ]
65
+ candidates = [p for p in contract_files() if FENCE.search(p.read_text(encoding="utf-8"))]
65
66
  if not candidates:
66
67
  raise ValueError(
67
68
  f"no ```design-doc-map fence in {[p.name for p in contract_files()]} at {REPO}"
@@ -160,9 +161,7 @@ def drift(doc: str, paths: list[str]) -> dict[str, object]:
160
161
  return {"doc": doc, "untracked": True, "added": [], "removed": [], "commits": 0}
161
162
 
162
163
  def modules(filt: str) -> list[str]:
163
- out = git(
164
- "diff", f"--diff-filter={filt}", "--name-only", f"{sha}..HEAD", "--", *paths
165
- )
164
+ out = git("diff", f"--diff-filter={filt}", "--name-only", f"{sha}..HEAD", "--", *paths)
166
165
  return [p for p in out.splitlines() if p and not IS_TEST.search(p)]
167
166
 
168
167
  return {
@@ -8,7 +8,7 @@ resolution-markers = [
8
8
 
9
9
  [[package]]
10
10
  name = "agent-usage-manager"
11
- version = "0.2.4"
11
+ version = "0.2.6"
12
12
  source = { editable = "." }
13
13
  dependencies = [
14
14
  { name = "fastapi", version = "0.128.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
@@ -1,31 +0,0 @@
1
- [build-system]
2
- requires = ["hatchling"]
3
- build-backend = "hatchling.build"
4
-
5
- [project]
6
- name = "agent-usage-manager"
7
- version = "0.2.5"
8
- description = "htop for AI agents — liveness, CPU/mem/GPU usage, and a kill switch for headless agents (openclaw, hermes, ollama, vllm, claude-code)."
9
- readme = "README.md"
10
- license = { text = "MIT" }
11
- requires-python = ">=3.9"
12
- keywords = ["ai-agents", "monitoring", "gpu", "ollama", "vllm", "llm", "observability"]
13
- dependencies = [
14
- "fastapi>=0.110",
15
- "uvicorn[standard]>=0.27",
16
- "psutil>=5.9",
17
- "pyyaml>=6.0",
18
- ]
19
-
20
- [project.optional-dependencies]
21
- dev = ["pytest>=7", "httpx>=0.27"]
22
-
23
- [project.urls]
24
- Homepage = "https://github.com/minglong51/agent-usage-manager"
25
- Repository = "https://github.com/minglong51/agent-usage-manager"
26
-
27
- [project.scripts]
28
- agent-usage-manager = "agent_usage_manager.cli:main"
29
-
30
- [tool.hatch.build.targets.wheel]
31
- packages = ["agent_usage_manager"]