By Sagar Shankaran, Founder of CallSphere
Design and build an internal marketplace where teams can discover, provision, and manage AI agents. Covers catalog design, self-service provisioning workflows, usage tracking, lifecycle management, and governance guardrails.
Key takeaways
As organizations adopt AI agents, a common pattern emerges. The data team builds a SQL agent. The support team builds a ticket triage agent. The legal team contracts a vendor for contract review. Within a year, there are fifteen agents across the company, and no one knows what exists, who owns each agent, or how much they cost.
An internal agent marketplace solves this discovery problem. It is a catalog where teams publish agents they have built, and other teams can browse, evaluate, and provision those agents for their own use. Think of it as an internal app store, but for AI agents.
The catalog stores metadata about each agent: what it does, who owns it, what data it accesses, and what approvals are required before a new team can use it.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from uuid import uuid4
class AgentStatus(str, Enum):
DRAFT = "draft"
PUBLISHED = "published"
DEPRECATED = "deprecated"
RETIRED = "retired"
class ApprovalRequirement(str, Enum):
NONE = "none"
MANAGER = "manager"
DATA_STEWARD = "data_steward"
SECURITY_REVIEW = "security_review"
@dataclass
class AgentCatalogEntry:
catalog_id: str = field(default_factory=lambda: str(uuid4()))
agent_id: str = ""
name: str = ""
short_description: str = ""
long_description: str = ""
category: str = ""
owner_team: str = ""
owner_email: str = ""
status: AgentStatus = AgentStatus.DRAFT
data_classification: str = "internal"
approval_required: ApprovalRequirement = ApprovalRequirement.NONE
supported_input_types: list[str] = field(default_factory=list)
example_prompts: list[str] = field(default_factory=list)
documentation_url: str = ""
cost_per_request_usd: float = 0.0
avg_latency_ms: int = 0
monthly_active_users: int = 0
satisfaction_score: float = 0.0
tags: list[str] = field(default_factory=list)
published_at: str | None = None
created_at: str = field(
default_factory=lambda: datetime.utcnow().isoformat()
)
class AgentCatalog:
def __init__(self, db_pool):
self.db = db_pool
async def search(
self,
query: str = "",
category: str = "",
status: AgentStatus = AgentStatus.PUBLISHED,
page: int = 1,
per_page: int = 20,
) -> dict:
conditions = ["status = $1"]
params: list = [status.value]
idx = 2
if query:
conditions.append(
f"(name ILIKE ${idx} OR short_description ILIKE ${idx} "
f"OR tags::text ILIKE ${idx})"
)
params.append(f"%{query}%")
idx += 1
if category:
conditions.append(f"category = ${idx}")
params.append(category)
idx += 1
where = " AND ".join(conditions)
offset = (page - 1) * per_page
rows = await self.db.fetch(
f"SELECT * FROM agent_catalog WHERE {where} "
f"ORDER BY monthly_active_users DESC "
f"LIMIT ${idx} OFFSET ${idx + 1}",
*params, per_page, offset,
)
total = await self.db.fetchval(
f"SELECT COUNT(*) FROM agent_catalog WHERE {where}",
*params,
)
return {
"agents": [dict(r) for r in rows],
"total": total,
"page": page,
}
When a team wants to use a published agent, they submit a provisioning request through the marketplace. The request flows through the approval chain defined in the catalog entry. Once approved, the platform automatically configures access: creates the team's role mapping, sets up usage quotas, and notifies the agent owner.
@dataclass
class ProvisioningRequest:
request_id: str = field(default_factory=lambda: str(uuid4()))
catalog_id: str = ""
requesting_team: str = ""
requesting_user: str = ""
business_justification: str = ""
estimated_monthly_usage: int = 0
cost_center: str = ""
status: str = "pending"
approvals: list[dict] = field(default_factory=list)
created_at: str = field(
default_factory=lambda: datetime.utcnow().isoformat()
)
class ProvisioningService:
def __init__(self, catalog: AgentCatalog, db_pool, notifier):
self.catalog = catalog
self.db = db_pool
self.notifier = notifier
async def submit_request(
self, request: ProvisioningRequest
) -> ProvisioningRequest:
entry = await self.db.fetchrow(
"SELECT * FROM agent_catalog WHERE catalog_id = $1",
request.catalog_id,
)
if not entry:
raise ValueError("Agent not found in catalog")
approval_req = entry["approval_required"]
if approval_req == "none":
request.status = "approved"
await self.provision_access(request, entry)
else:
request.status = "pending_approval"
await self.notifier.request_approval(
approver_type=approval_req,
request=request,
agent_name=entry["name"],
)
await self.save_request(request)
return request
async def provision_access(self, request, catalog_entry) -> None:
await self.db.execute(
"""
INSERT INTO agent_access (
team, agent_id, cost_center,
monthly_quota, granted_at
) VALUES ($1, $2, $3, $4, NOW())
""",
request.requesting_team, catalog_entry["agent_id"],
request.cost_center, request.estimated_monthly_usage,
)
await self.notifier.send(
to=request.requesting_user,
subject=f"Access granted: {catalog_entry['name']}",
body=f"Your team now has access to {catalog_entry['name']}.",
)
Every provisioned agent tracks usage per team. When usage drops to zero for 90 days, the system flags the provisioning for review. Agent owners can deprecate agents, which triggers a migration notification to all active teams. Retired agents are removed from the catalog but remain accessible for 30 days to allow migrations.
Before an agent can be published to the marketplace, it must pass quality gates: documentation completeness, evaluation score above a threshold, security review for data access patterns, and cost estimate accuracy. This prevents the catalog from filling with low-quality or abandoned agents.
Implement health scores based on owner responsiveness, update frequency, user satisfaction, and incident history. Agents below a health threshold get a "needs attention" badge. If the owner does not respond within 30 days, the agent moves to "deprecated" status automatically. Quarterly reviews with agent owners keep the catalog clean and current.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
Chargebacks create accountability. When agents are free, teams provision everything and use nothing, cluttering the catalog with phantom adoption. Even a lightweight showback model — showing teams their usage costs without actually charging — changes behavior. Teams start questioning whether they need five agents or two.
Use parameterized agent configurations. The base agent logic is shared, but each team's provisioning includes data access scopes. The support team's instance connects to the support ticket database, while the sales team's instance connects to the CRM. The marketplace handles this through provisioning templates that configure data sources per team.
#EnterpriseAI #Marketplace #SelfService #AgentCatalog #Provisioning #LifecycleManagement #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
A three-way comparison of Gemini Enterprise, Anthropic managed agents and OpenAI Frontier Platform after Cloud Next 2026 — strengths, gaps, buyer fit.
ServiceNow Project Arc vs Anthropic Managed Agents — runtime, governance, integration, and use cases. The 2026 enterprise autonomous agent comparison.
A2A unlocks cross-vendor agent coordination, but most enterprise voice/chat workloads still ship faster on a single-vendor stack. Here is how to choose.
Working memory, permanent memory, sandboxes, harnesses, governance — the practical blueprint enterprises are using to ship long-horizon AI agents in 2026.
AI Control Tower is the governance layer for ServiceNow's Project Arc — policy, monitoring, and audit logs for autonomous agents. Here is how it works.
Anthropic announced full Microsoft 365 integration in May 2026. What the integration covers, what it means for Outlook, Word, Excel, and Teams users, and where the boundaries are.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.