agent-catalog-new 0.2.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 (43) hide show
  1. agent_catalog_new-0.2.0/LICENSE +21 -0
  2. agent_catalog_new-0.2.0/PKG-INFO +201 -0
  3. agent_catalog_new-0.2.0/README.md +173 -0
  4. agent_catalog_new-0.2.0/agent_catalog/__init__.py +33 -0
  5. agent_catalog_new-0.2.0/agent_catalog/cli/__init__.py +108 -0
  6. agent_catalog_new-0.2.0/agent_catalog/cli/__main__.py +3 -0
  7. agent_catalog_new-0.2.0/agent_catalog/cli/aux_commands.py +139 -0
  8. agent_catalog_new-0.2.0/agent_catalog/cli/crud.py +192 -0
  9. agent_catalog_new-0.2.0/agent_catalog/cli/diff_commands.py +165 -0
  10. agent_catalog_new-0.2.0/agent_catalog/cli/discover_commands.py +190 -0
  11. agent_catalog_new-0.2.0/agent_catalog/client.py +340 -0
  12. agent_catalog_new-0.2.0/agent_catalog/config.py +120 -0
  13. agent_catalog_new-0.2.0/agent_catalog/decorators.py +549 -0
  14. agent_catalog_new-0.2.0/agent_catalog/diff.py +156 -0
  15. agent_catalog_new-0.2.0/agent_catalog/discovery.py +177 -0
  16. agent_catalog_new-0.2.0/agent_catalog/graph.py +87 -0
  17. agent_catalog_new-0.2.0/agent_catalog/loader.py +161 -0
  18. agent_catalog_new-0.2.0/agent_catalog/mcp_server.py +279 -0
  19. agent_catalog_new-0.2.0/agent_catalog/py.typed +0 -0
  20. agent_catalog_new-0.2.0/agent_catalog/schema.py +252 -0
  21. agent_catalog_new-0.2.0/agent_catalog/security.py +101 -0
  22. agent_catalog_new-0.2.0/agent_catalog/serve.py +397 -0
  23. agent_catalog_new-0.2.0/agent_catalog/storage.py +280 -0
  24. agent_catalog_new-0.2.0/agent_catalog_new.egg-info/PKG-INFO +201 -0
  25. agent_catalog_new-0.2.0/agent_catalog_new.egg-info/SOURCES.txt +41 -0
  26. agent_catalog_new-0.2.0/agent_catalog_new.egg-info/dependency_links.txt +1 -0
  27. agent_catalog_new-0.2.0/agent_catalog_new.egg-info/entry_points.txt +2 -0
  28. agent_catalog_new-0.2.0/agent_catalog_new.egg-info/requires.txt +10 -0
  29. agent_catalog_new-0.2.0/agent_catalog_new.egg-info/top_level.txt +1 -0
  30. agent_catalog_new-0.2.0/pyproject.toml +83 -0
  31. agent_catalog_new-0.2.0/setup.cfg +4 -0
  32. agent_catalog_new-0.2.0/tests/test_cli.py +500 -0
  33. agent_catalog_new-0.2.0/tests/test_client.py +30 -0
  34. agent_catalog_new-0.2.0/tests/test_coverage_gaps.py +456 -0
  35. agent_catalog_new-0.2.0/tests/test_decorators.py +404 -0
  36. agent_catalog_new-0.2.0/tests/test_diff.py +69 -0
  37. agent_catalog_new-0.2.0/tests/test_discovery.py +205 -0
  38. agent_catalog_new-0.2.0/tests/test_features.py +186 -0
  39. agent_catalog_new-0.2.0/tests/test_loader.py +216 -0
  40. agent_catalog_new-0.2.0/tests/test_mcp_server.py +143 -0
  41. agent_catalog_new-0.2.0/tests/test_schema.py +102 -0
  42. agent_catalog_new-0.2.0/tests/test_schema_full.py +521 -0
  43. agent_catalog_new-0.2.0/tests/test_storage.py +85 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ervin
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,201 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-catalog-new
3
+ Version: 0.2.0
4
+ Summary: Declarative agent registry — catalog, discover, and diff agent capabilities across environments
5
+ Author-email: Ervin <ervin@nexusgate.tech>
6
+ License: MIT
7
+ Keywords: agents,catalog,registry,ai-agents,agent-management,mcp
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Topic :: Software Development :: Libraries
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest<10,>=9.0; extra == "dev"
21
+ Requires-Dist: pytest-cov<8,>=7.0; extra == "dev"
22
+ Requires-Dist: ruff<1,>=0.15; extra == "dev"
23
+ Requires-Dist: coverage[toml]<8,>=7.6; extra == "dev"
24
+ Requires-Dist: mypy>=1.15; extra == "dev"
25
+ Provides-Extra: mcp
26
+ Requires-Dist: mcp<2,>=1.0; extra == "mcp"
27
+ Dynamic: license-file
28
+
29
+ # Agent Catalog
30
+
31
+ [![CI](https://github.com/ewardGPT/agent-catalog/actions/workflows/ci.yml/badge.svg)](https://github.com/ewardGPT/agent-catalog/actions/workflows/ci.yml)
32
+ [![PyPI](https://img.shields.io/pypi/v/agent-catalog)](https://pypi.org/project/agent-catalog/)
33
+ [![Python](https://img.shields.io/pypi/pyversions/agent-catalog)](https://pypi.org/project/agent-catalog/)
34
+ [![License](https://img.shields.io/github/license/ewardGPT/agent-catalog)](LICENSE)
35
+
36
+ A registry for AI agents. Track every agent you own — what it does, what tools it uses, what model it runs, where it's deployed. YAML manifests stored on disk. No database. Git-ops friendly.
37
+
38
+ Think `npm` for agents. One tool to list, search, diff, and invoke them all.
39
+
40
+ ```bash
41
+ pip install agent-catalog
42
+ agent-catalog register ./my-agent.yaml
43
+ agent-catalog list
44
+ ```
45
+
46
+ ## Why
47
+
48
+ You have agents scattered across repos, environments, and projects. Prod vs staging drift goes unnoticed. A dependency changes and nothing tells you. You grep through directories to find which agent has the capability you need.
49
+
50
+ Agent Catalog fixes that. One directory is the source of truth. Every command queries it.
51
+
52
+ ## Features
53
+
54
+ - **Registry.** Register agents from YAML manifests. List, search, get details. Filter by environment, capability, tool, surface.
55
+ - **Diff.** Compare manifests across environments (`--left-env staging --right-env production`). Catch drift before it hits prod.
56
+ - **Consistency.** `agent-catalog doctor` finds orphaned files and missing manifests.
57
+ - **Security audit.** Flags MCP endpoints without auth, write capabilities without confirmation gates, idempotent tools that should not be.
58
+ - **MCP server.** Expose the catalog as MCP tools — any MCP client can discover agents and invoke their capabilities.
59
+ - **HTTP dashboard.** `agent-catalog serve` starts a web UI on `:8420`.
60
+ - **Python SDK.** `from agent_catalog.client import CatalogClient` — sync or async.
61
+ - **Decorator API.** Define agents inline with `@agent`, `@capability`, `@tool`. Manifests auto-generated from Python classes.
62
+ - **Runtime loader.** Load an agent class from the catalog and invoke a capability from the command line or API.
63
+
64
+ ## Quick start
65
+
66
+ ```bash
67
+ pip install agent-catalog
68
+
69
+ # Register an agent
70
+ agent-catalog register ./examples/agentic-inbox.yaml
71
+
72
+ # See everything you have
73
+ agent-catalog list
74
+
75
+ # Get details
76
+ agent-catalog get agentic-inbox
77
+
78
+ # Search
79
+ agent-catalog search --capability send_email
80
+
81
+ # Validate a manifest without registering
82
+ agent-catalog validate ./my-agent.yaml
83
+ ```
84
+
85
+ ## Walkthrough: managing agents across environments
86
+
87
+ ```bash
88
+ # Register your staging agent
89
+ agent-catalog register ./staging/agent.yaml --env staging
90
+
91
+ # Later, register production
92
+ agent-catalog register ./prod/agent.yaml
93
+
94
+ # See the drift
95
+ agent-catalog diff agentic-inbox --left-env staging --right-env production
96
+
97
+ # Validate your changes
98
+ agent-catalog validate ./prod/agent.yaml
99
+
100
+ # Check everything is consistent
101
+ agent-catalog doctor
102
+ ```
103
+
104
+ ## Walkthrough: exposing agents via MCP
105
+
106
+ ```bash
107
+ # Start the MCP server
108
+ agent-catalog serve --mcp
109
+
110
+ # Any MCP client can now call:
111
+ # - catalog_list_agents
112
+ # - catalog_get_agent
113
+ # - catalog_search
114
+ # - catalog_invoke
115
+ ```
116
+
117
+ ## Walkthrough: Python SDK
118
+
119
+ ```python
120
+ from agent_catalog.client import CatalogClient
121
+
122
+ client = CatalogClient()
123
+
124
+ # List all production agents
125
+ for agent in client.agents.list(env="production"):
126
+ print(agent.slug, agent.capability_ids())
127
+
128
+ # Async
129
+ from agent_catalog.client import AsyncCatalogClient
130
+ client = AsyncCatalogClient()
131
+ agents = await client.agents.list()
132
+ ```
133
+
134
+ ## Walkthrough: decorator API
135
+
136
+ ```python
137
+ from agent_catalog import agent, capability, tool, build_manifest
138
+
139
+ @agent(name="My Agent", version="1.0.0", environment="production")
140
+ class MyAgent:
141
+ @capability(id="greet", description="Greets the user")
142
+ @tool(name="greet", description="Say hello")
143
+ def greet(self, name: str) -> str:
144
+ return f"Hello, {name}!"
145
+
146
+ manifest = build_manifest(MyAgent)
147
+ ```
148
+
149
+ ## Commands
150
+
151
+ | Command | Action |
152
+ |---------|--------|
153
+ | `register <path>` | Register agent from YAML |
154
+ | `list [--env] [--output json]` | List agents |
155
+ | `get <slug> [--output json]` | Show agent details |
156
+ | `search [--capability] [--tool] [--surface] [--env]` | Find agents |
157
+ | `diff <slug> [--right] [--slug2] [--right-env]` | Compare manifests |
158
+ | `validate <path>` | Validate YAML |
159
+ | `unregister <slug>` | Remove agent |
160
+ | `update <slug> <path>` | Update manifest |
161
+ | `sync <dir> [--pattern]` | Bulk register YAML files |
162
+ | `scan <dir>` | Discover @agent-decorated Python classes |
163
+ | `inspect <file>` | Show manifest from Python file |
164
+ | `export-contract <slug>` | Export eval contract |
165
+ | `security-audit [--format json]` | Security audit |
166
+ | `graph [--format json]` | Dependency graph |
167
+ | `serve [--port] [--mcp]` | HTTP dashboard or MCP server |
168
+ | `run <slug> <capability>` | Invoke a capability |
169
+ | `doctor` | Consistency check |
170
+
171
+ ## Storage
172
+
173
+ Manifests are YAML files in `~/.config/agent-catalog/agents/`. `index.yaml` maps slugs to filenames. Set `AGENT_CATALOG_DIR` to point at a git repo — changes show up in `git diff`.
174
+
175
+ ```
176
+ ~/.config/agent-catalog/agents/
177
+ ├── index.yaml # slug → filename mapping
178
+ ├── agentic-inbox.yaml # agent manifests
179
+ ├── nexusgate.yaml
180
+ └── trading-agent.yaml
181
+ ```
182
+
183
+ ## Production features
184
+
185
+ - **Atomic writes.** Every write goes to a temp file then `os.replace()` — no partial writes on crash.
186
+ - **Slug validation.** Rejects path traversal characters (/, \\, .., null).
187
+ - **Index cache.** Repeated `index()` calls within one invocation skip re-parsing.
188
+ - **Config validation.** Warns on type errors and unknown keys in config.yaml.
189
+ - **Consistency check.** `doctor` command finds orphaned files and missing manifests.
190
+ - **XSS-safe dashboard.** All agent values HTML-escaped.
191
+ - **CORS headers.** JSON API supports cross-origin requests.
192
+ - **Graceful shutdown.** SIGINT/SIGTERM signal handlers on HTTP server.
193
+ - **MCP token budget.** Tool responses hard-truncated to 1500 chars.
194
+
195
+ ## Contributing
196
+
197
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
198
+
199
+ ## License
200
+
201
+ MIT
@@ -0,0 +1,173 @@
1
+ # Agent Catalog
2
+
3
+ [![CI](https://github.com/ewardGPT/agent-catalog/actions/workflows/ci.yml/badge.svg)](https://github.com/ewardGPT/agent-catalog/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/agent-catalog)](https://pypi.org/project/agent-catalog/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/agent-catalog)](https://pypi.org/project/agent-catalog/)
6
+ [![License](https://img.shields.io/github/license/ewardGPT/agent-catalog)](LICENSE)
7
+
8
+ A registry for AI agents. Track every agent you own — what it does, what tools it uses, what model it runs, where it's deployed. YAML manifests stored on disk. No database. Git-ops friendly.
9
+
10
+ Think `npm` for agents. One tool to list, search, diff, and invoke them all.
11
+
12
+ ```bash
13
+ pip install agent-catalog
14
+ agent-catalog register ./my-agent.yaml
15
+ agent-catalog list
16
+ ```
17
+
18
+ ## Why
19
+
20
+ You have agents scattered across repos, environments, and projects. Prod vs staging drift goes unnoticed. A dependency changes and nothing tells you. You grep through directories to find which agent has the capability you need.
21
+
22
+ Agent Catalog fixes that. One directory is the source of truth. Every command queries it.
23
+
24
+ ## Features
25
+
26
+ - **Registry.** Register agents from YAML manifests. List, search, get details. Filter by environment, capability, tool, surface.
27
+ - **Diff.** Compare manifests across environments (`--left-env staging --right-env production`). Catch drift before it hits prod.
28
+ - **Consistency.** `agent-catalog doctor` finds orphaned files and missing manifests.
29
+ - **Security audit.** Flags MCP endpoints without auth, write capabilities without confirmation gates, idempotent tools that should not be.
30
+ - **MCP server.** Expose the catalog as MCP tools — any MCP client can discover agents and invoke their capabilities.
31
+ - **HTTP dashboard.** `agent-catalog serve` starts a web UI on `:8420`.
32
+ - **Python SDK.** `from agent_catalog.client import CatalogClient` — sync or async.
33
+ - **Decorator API.** Define agents inline with `@agent`, `@capability`, `@tool`. Manifests auto-generated from Python classes.
34
+ - **Runtime loader.** Load an agent class from the catalog and invoke a capability from the command line or API.
35
+
36
+ ## Quick start
37
+
38
+ ```bash
39
+ pip install agent-catalog
40
+
41
+ # Register an agent
42
+ agent-catalog register ./examples/agentic-inbox.yaml
43
+
44
+ # See everything you have
45
+ agent-catalog list
46
+
47
+ # Get details
48
+ agent-catalog get agentic-inbox
49
+
50
+ # Search
51
+ agent-catalog search --capability send_email
52
+
53
+ # Validate a manifest without registering
54
+ agent-catalog validate ./my-agent.yaml
55
+ ```
56
+
57
+ ## Walkthrough: managing agents across environments
58
+
59
+ ```bash
60
+ # Register your staging agent
61
+ agent-catalog register ./staging/agent.yaml --env staging
62
+
63
+ # Later, register production
64
+ agent-catalog register ./prod/agent.yaml
65
+
66
+ # See the drift
67
+ agent-catalog diff agentic-inbox --left-env staging --right-env production
68
+
69
+ # Validate your changes
70
+ agent-catalog validate ./prod/agent.yaml
71
+
72
+ # Check everything is consistent
73
+ agent-catalog doctor
74
+ ```
75
+
76
+ ## Walkthrough: exposing agents via MCP
77
+
78
+ ```bash
79
+ # Start the MCP server
80
+ agent-catalog serve --mcp
81
+
82
+ # Any MCP client can now call:
83
+ # - catalog_list_agents
84
+ # - catalog_get_agent
85
+ # - catalog_search
86
+ # - catalog_invoke
87
+ ```
88
+
89
+ ## Walkthrough: Python SDK
90
+
91
+ ```python
92
+ from agent_catalog.client import CatalogClient
93
+
94
+ client = CatalogClient()
95
+
96
+ # List all production agents
97
+ for agent in client.agents.list(env="production"):
98
+ print(agent.slug, agent.capability_ids())
99
+
100
+ # Async
101
+ from agent_catalog.client import AsyncCatalogClient
102
+ client = AsyncCatalogClient()
103
+ agents = await client.agents.list()
104
+ ```
105
+
106
+ ## Walkthrough: decorator API
107
+
108
+ ```python
109
+ from agent_catalog import agent, capability, tool, build_manifest
110
+
111
+ @agent(name="My Agent", version="1.0.0", environment="production")
112
+ class MyAgent:
113
+ @capability(id="greet", description="Greets the user")
114
+ @tool(name="greet", description="Say hello")
115
+ def greet(self, name: str) -> str:
116
+ return f"Hello, {name}!"
117
+
118
+ manifest = build_manifest(MyAgent)
119
+ ```
120
+
121
+ ## Commands
122
+
123
+ | Command | Action |
124
+ |---------|--------|
125
+ | `register <path>` | Register agent from YAML |
126
+ | `list [--env] [--output json]` | List agents |
127
+ | `get <slug> [--output json]` | Show agent details |
128
+ | `search [--capability] [--tool] [--surface] [--env]` | Find agents |
129
+ | `diff <slug> [--right] [--slug2] [--right-env]` | Compare manifests |
130
+ | `validate <path>` | Validate YAML |
131
+ | `unregister <slug>` | Remove agent |
132
+ | `update <slug> <path>` | Update manifest |
133
+ | `sync <dir> [--pattern]` | Bulk register YAML files |
134
+ | `scan <dir>` | Discover @agent-decorated Python classes |
135
+ | `inspect <file>` | Show manifest from Python file |
136
+ | `export-contract <slug>` | Export eval contract |
137
+ | `security-audit [--format json]` | Security audit |
138
+ | `graph [--format json]` | Dependency graph |
139
+ | `serve [--port] [--mcp]` | HTTP dashboard or MCP server |
140
+ | `run <slug> <capability>` | Invoke a capability |
141
+ | `doctor` | Consistency check |
142
+
143
+ ## Storage
144
+
145
+ Manifests are YAML files in `~/.config/agent-catalog/agents/`. `index.yaml` maps slugs to filenames. Set `AGENT_CATALOG_DIR` to point at a git repo — changes show up in `git diff`.
146
+
147
+ ```
148
+ ~/.config/agent-catalog/agents/
149
+ ├── index.yaml # slug → filename mapping
150
+ ├── agentic-inbox.yaml # agent manifests
151
+ ├── nexusgate.yaml
152
+ └── trading-agent.yaml
153
+ ```
154
+
155
+ ## Production features
156
+
157
+ - **Atomic writes.** Every write goes to a temp file then `os.replace()` — no partial writes on crash.
158
+ - **Slug validation.** Rejects path traversal characters (/, \\, .., null).
159
+ - **Index cache.** Repeated `index()` calls within one invocation skip re-parsing.
160
+ - **Config validation.** Warns on type errors and unknown keys in config.yaml.
161
+ - **Consistency check.** `doctor` command finds orphaned files and missing manifests.
162
+ - **XSS-safe dashboard.** All agent values HTML-escaped.
163
+ - **CORS headers.** JSON API supports cross-origin requests.
164
+ - **Graceful shutdown.** SIGINT/SIGTERM signal handlers on HTTP server.
165
+ - **MCP token budget.** Tool responses hard-truncated to 1500 chars.
166
+
167
+ ## Contributing
168
+
169
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
170
+
171
+ ## License
172
+
173
+ MIT
@@ -0,0 +1,33 @@
1
+ """Agent Catalog — Declarative agent registry.
2
+
3
+ Discover, diff, and manage agent capabilities across environments.
4
+
5
+ Decorator API (new in 0.2.0):
6
+
7
+ from agent_catalog import agent, capability, tool, interface, dependency
8
+ from agent_catalog.decorators import build_manifest
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from agent_catalog.decorators import (
14
+ agent,
15
+ build_manifest,
16
+ capability,
17
+ dependency,
18
+ interface,
19
+ prompt_ref,
20
+ tool,
21
+ )
22
+
23
+ __all__ = [
24
+ "agent",
25
+ "build_manifest",
26
+ "capability",
27
+ "dependency",
28
+ "interface",
29
+ "prompt_ref",
30
+ "tool",
31
+ ]
32
+
33
+ __version__ = "0.2.0"
@@ -0,0 +1,108 @@
1
+ """Agent Catalog CLI — declarative agent registry.
2
+
3
+ Usage:
4
+ agent-catalog register ./agent.yaml
5
+ agent-catalog list
6
+ agent-catalog get agentic-inbox
7
+ agent-catalog search --capability send_email
8
+ agent-catalog diff agentic-inbox --right staging
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import os
14
+
15
+ import typer
16
+ from rich.console import Console
17
+ from rich.panel import Panel
18
+ from rich.text import Text
19
+
20
+ from agent_catalog import __version__
21
+ from agent_catalog.storage import CatalogStore
22
+
23
+ # ── App ────────────────────────────────────────────────────────────────────────
24
+
25
+ app = typer.Typer(
26
+ name="agent-catalog",
27
+ help="Declarative agent registry — catalog, discover, and diff agent capabilities.",
28
+ no_args_is_help=True,
29
+ )
30
+
31
+ # Typer adds --install-completion and --show-completion automatically.
32
+
33
+ console = Console()
34
+
35
+
36
+ # ── Version flag ────────────────────────────────────────────────────────────────
37
+
38
+
39
+ def _version_callback(value: bool) -> None:
40
+ if value:
41
+ console.print(f"agent-catalog {__version__}")
42
+ raise typer.Exit()
43
+
44
+
45
+ @app.callback()
46
+ def _main_options(
47
+ version: bool = typer.Option(
48
+ False,
49
+ "--version",
50
+ help="Show version and exit.",
51
+ callback=_version_callback,
52
+ is_eager=True,
53
+ ),
54
+ ) -> None:
55
+ """Agent Catalog — declarative agent registry."""
56
+
57
+
58
+ # ── Shared helpers ─────────────────────────────────────────────────────────────
59
+
60
+
61
+ def _get_store() -> CatalogStore:
62
+ """Resolve the catalog store, respecting AGENT_CATALOG_DIR env var."""
63
+ root = os.environ.get("AGENT_CATALOG_DIR")
64
+ return CatalogStore(root=root) if root else CatalogStore()
65
+
66
+
67
+ def _render_manifest(m) -> Panel:
68
+ """Pretty-print an agent manifest as a Rich Panel."""
69
+ rows: list[str] = []
70
+ rows.append(f"[bold]Name:[/] {m.name}")
71
+ rows.append(f"[bold]Slug:[/] {m.slug}")
72
+ rows.append(f"[bold]Version:[/] {m.version}")
73
+ rows.append(f"[bold]Environment:[/] {m.environment}")
74
+ rows.append(f"[bold]Status:[/] {m.status}")
75
+ rows.append(f"[bold]Description:[/] {m.description}")
76
+ if m.model:
77
+ rows.append(f"[bold]Model:[/] {m.model.provider}/{m.model.name}")
78
+ if m.capabilities:
79
+ rows.append(f"[bold]Capabilities:[/] {', '.join(c.id for c in m.capabilities)}")
80
+ if m.tools:
81
+ rows.append(f"[bold]Tools:[/] {', '.join(t.name for t in m.tools)}")
82
+ if m.prompt:
83
+ versions = ", ".join(p.version for p in m.prompt)
84
+ rows.append(f"[bold]Prompts:[/] {versions}")
85
+ if m.dependencies:
86
+ deps = ", ".join(d.name for d in m.dependencies)
87
+ rows.append(f"[bold]Dependencies:[/] {deps}")
88
+ if m.eval_contract:
89
+ suites = ", ".join(m.eval_contract.suites)
90
+ rows.append(f"[bold]Eval Suites:[/] {suites}")
91
+ text = "\n".join(rows)
92
+ return Panel(Text.from_markup(text), title=m.environment_tag())
93
+
94
+
95
+ # ── Entry point ────────────────────────────────────────────────────────────────
96
+
97
+
98
+ def main() -> None:
99
+ """Entry point for the 'agent-catalog' command."""
100
+ app()
101
+
102
+
103
+ if __name__ == "__main__":
104
+ main()
105
+
106
+ # ── Register subcommand modules ────────────────────────────────────────────────
107
+
108
+ from . import aux_commands, crud, diff_commands, discover_commands # noqa: E402,F401
@@ -0,0 +1,3 @@
1
+ from agent_catalog.cli import app
2
+
3
+ app()
@@ -0,0 +1,139 @@
1
+ """Auxiliary commands: security-audit, graph, serve, run, doctor."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+
7
+ import typer
8
+
9
+ from agent_catalog.cli import _get_store, app, console
10
+
11
+
12
+ @app.command()
13
+ def security_audit(
14
+ output_format: str = typer.Option("table", "--format", "-f", help="Output: table, json"),
15
+ ):
16
+ """Audit all registered agents for security gaps."""
17
+ from agent_catalog.security import audit_catalog
18
+
19
+ findings = audit_catalog(_get_store())
20
+ if not findings:
21
+ console.print("[green]No security issues found[/]")
22
+ return
23
+
24
+ if output_format == "json":
25
+ console.print(
26
+ json.dumps(
27
+ [
28
+ {"severity": f.severity, "agent": f.agent, "title": f.title, "detail": f.detail}
29
+ for f in findings
30
+ ],
31
+ indent=2,
32
+ )
33
+ )
34
+ return
35
+
36
+ from rich.table import Table
37
+
38
+ table = Table(title="Security Audit")
39
+ table.add_column("Severity", style="bold")
40
+ table.add_column("Agent")
41
+ table.add_column("Issue")
42
+ table.add_column("Detail", style="dim")
43
+
44
+ for f in findings:
45
+ color = {"critical": "red", "high": "yellow", "medium": "dim", "low": "dim"}[f.severity]
46
+ table.add_row(f"[{color}]{f.severity}[/]", f.agent, f.title, f.detail)
47
+
48
+ console.print(table)
49
+ crit = sum(1 for f in findings if f.severity == "critical")
50
+ high = sum(1 for f in findings if f.severity == "high")
51
+ console.print(f"[bold]Summary:[/] {len(findings)} findings ({crit} critical, {high} high)")
52
+
53
+
54
+ @app.command()
55
+ def graph(
56
+ output_format: str = typer.Option("mermaid", "--format", "-f", help="Output: mermaid, json"),
57
+ ):
58
+ """Show agent dependency graph."""
59
+ from agent_catalog.graph import build_graph, to_mermaid
60
+
61
+ store = _get_store()
62
+ if output_format == "json":
63
+ console.print_json(json.dumps(build_graph(store), default=str))
64
+ else:
65
+ console.print(to_mermaid(store))
66
+
67
+
68
+ @app.command()
69
+ def serve(
70
+ port: int = typer.Option(8420, "--port", "-p", help="HTTP port"),
71
+ mcp: bool = typer.Option(False, "--mcp", help="Run MCP server instead of HTTP (stdio transport)"),
72
+ ):
73
+ """Start the Agent Marketplace web dashboard.
74
+
75
+ By default starts an HTTP server. Pass --mcp to run as an MCP
76
+ server over stdio (for use with MCP clients like Claude Code).
77
+ """
78
+ if mcp:
79
+ from agent_catalog.mcp_server import run_server
80
+
81
+ run_server(store=_get_store())
82
+ else:
83
+ from agent_catalog.serve import serve as run_serve
84
+
85
+ run_serve(port=port, store=_get_store())
86
+
87
+
88
+ @app.command()
89
+ def run(
90
+ slug: str = typer.Argument(..., help="Agent slug"),
91
+ capability: str = typer.Argument(..., help="Capability ID to invoke"),
92
+ params: str | None = typer.Option(None, "--params", "-p", help="JSON string of parameters"),
93
+ ):
94
+ """Load an agent and invoke a capability at runtime.
95
+
96
+ Uses metadata.python_module / metadata.python_class to find and
97
+ import the agent class, then calls the capability method.
98
+
99
+ Examples:
100
+ agent-catalog run my-agent greet
101
+ agent-catalog run my-agent greet --params '{"name": "World"}'
102
+ """
103
+ from agent_catalog.loader import invoke_capability
104
+
105
+ kwargs: dict = {}
106
+ if params:
107
+ try:
108
+ kwargs = json.loads(params)
109
+ except json.JSONDecodeError as e:
110
+ console.print(f"[red]\u2717[/] Invalid JSON in --params: {e}")
111
+ raise typer.Exit(1) from e
112
+
113
+ try:
114
+ result = invoke_capability(slug, capability, store=_get_store(), **kwargs)
115
+ console.print(result)
116
+ except Exception as e:
117
+ console.print(f"[red]\u2717[/] {e}")
118
+ raise typer.Exit(1) from e
119
+
120
+
121
+ @app.command()
122
+ def doctor():
123
+ """Check catalog consistency (orphaned files, missing manifests).
124
+
125
+ Scans the catalog directory and verifies every indexed agent
126
+ has a manifest file on disk, and every YAML file is indexed.
127
+ """
128
+ store = _get_store()
129
+ issues = store.check_consistency()
130
+
131
+ if not issues:
132
+ console.print("[green]\u2713[/] Catalog is consistent")
133
+ return
134
+
135
+ console.print(f"[yellow]Found {len(issues)} issue(s):[/]")
136
+ for issue in issues:
137
+ prefix = "[red]MISSING[/]" if issue.startswith("MISSING") else "[yellow]ORPHAN[/]"
138
+ console.print(f" {prefix} {issue}")
139
+ raise typer.Exit(1)