From Discovery to Agents: Building an Automatic Agent Type Recommender
TL;DR
- The Agent Recommender turns Discovery Engine's enterprise formation into a ranked, deduplicated list of which AI agents your org should deploy.
- Four independent strategies (team-based, service-based, tech-stack, gap analysis) converge on recommendations with priority scores and one-click provisioning.
- 548 lines of core logic, 56 unit tests. Live now.
Discovery Engine can map your organization -- teams, services, tech stacks, cloud infrastructure. That map is useful. But it immediately raises the harder question: now what? You know what your org looks like. Which agents should you deploy to cover it?
In a cyborgenic organization -- where AI agents and humans share operational responsibility -- the answer cannot be "have someone manually pick agent types from a catalog." That approach does not scale, and it is already out of date by the time you finish. A mid-size engineering org has dozens of teams, hundreds of services, and a tech stack that evolves monthly.
So we built the Agent Recommender. It takes the enterprise formation that Discovery Engine produces and automatically recommends which agent types to deploy -- with deduplication, priority scoring, and one-click provisioning. 548 lines of core logic, 109 lines of API surface, and 56 unit tests.
Here is how it works.
The Flow
The full pipeline looks like this:
- Discovery Engine scans your GitHub org, Slack workspace, and cloud providers
- It builds an enterprise formation — a structured representation of your teams, services, languages, and infrastructure
- Agent Recommender analyzes the formation using four recommendation strategies
- It produces a ranked list of agent types with priority scores and template configs
- You review and provision with one click (or one API call)
The recommender sits between discovery and provisioning. It's the decision layer — the thing that turns raw organizational data into actionable agent deployment plans.
Four Recommendation Strategies
The recommender doesn't use a single heuristic. It runs four independent strategies against the enterprise formation, then merges and deduplicates the results. Each strategy catches a different signal.
Strategy 1: Team-Based Mapping
The simplest and often most accurate signal: if your org has a team, it probably needs a corresponding agent.
TEAM_AGENT_MAP = {
"payments-team": "backend-lead",
"frontend-team": "frontend-lead",
"platform-team": "devops-lead",
"data-team": "data-engineer",
"security-team": "security-specialist",
"ml-team": "ml-engineer",
}
def recommend_by_teams(self, formation: EnterpriseFormation) -> list[AgentRecommendation]:
recommendations = []
for team in formation.teams:
normalized = self._normalize_team_name(team.name)
if agent_type := self.TEAM_AGENT_MAP.get(normalized):
recommendations.append(AgentRecommendation(
agent_type=agent_type,
source_strategy="team-based",
source_entity=team.name,
priority=team.member_count * 0.5 + team.activity_score * 0.5,
template_config=self.get_template(agent_type),
))
return recommendations
The priority score weights team size and activity equally. A 20-person payments team that's active daily gets a higher score than a 3-person experimental team that had one commit last month. That priority matters downstream when you're deciding what to provision first.
Team name normalization handles the variations you'd expect — payments, payments-team, team-payments, payments_eng all resolve to the same agent type. If you've ever tried to match team names across GitHub and Slack, you know why this matters.
Strategy 2: Service-Based Mapping
Teams are one signal. But not every service belongs to a neatly labeled team. The service-based strategy looks at what's actually running.
def recommend_by_services(self, formation: EnterpriseFormation) -> list[AgentRecommendation]:
recommendations = []
for service in formation.services:
agent_type = self._classify_service(service)
if agent_type:
recommendations.append(AgentRecommendation(
agent_type=agent_type,
source_strategy="service-based",
source_entity=service.name,
priority=self._service_priority(service),
template_config=self.get_template(agent_type),
))
return recommendations
Service classification looks at the service type, its API surface, and its dependencies. An API gateway service maps to an API specialist agent. A data pipeline service maps to a data engineer. A monitoring service maps to an SRE agent.
The classification isn't keyword matching — it examines the service's characteristics as discovered by Discovery Engine. A service with REST endpoints, rate limiting, and auth middleware gets classified as an API service even if nobody named it api-gateway.
Strategy 3: Tech Stack Mapping
Your tech stack determines what kind of expertise your agents need. A React frontend and a Go backend need different specialists.
TECH_AGENT_MAP = {
"react": "frontend-agent",
"vue": "frontend-agent",
"angular": "frontend-agent",
"python": "backend-agent",
"go": "backend-agent",
"rust": "systems-agent",
"terraform": "infra-agent",
"kubernetes": "devops-agent",
"pytorch": "ml-agent",
"tensorflow": "ml-agent",
}
def recommend_by_tech_stack(self, formation: EnterpriseFormation) -> list[AgentRecommendation]:
recommendations = []
for tech in formation.tech_stack:
if agent_type := self.TECH_AGENT_MAP.get(tech.name.lower()):
recommendations.append(AgentRecommendation(
agent_type=agent_type,
source_strategy="tech-stack",
source_entity=tech.name,
priority=tech.repo_count * 0.4 + tech.contributor_count * 0.6,
template_config=self.get_template(agent_type),
))
return recommendations
Priority here weights contributor count more heavily than repo count. A language used by 15 developers across 3 repos is more important than a language used in 10 repos by 2 developers. You want agents where the people are.
Strategy 4: Gap Analysis
The most interesting strategy. It doesn't look at what exists — it looks at what's missing.
def recommend_by_gaps(self, formation: EnterpriseFormation,
existing_agents: list[str]) -> list[AgentRecommendation]:
all_needed = set()
for strategy in [self.recommend_by_teams, self.recommend_by_services,
self.recommend_by_tech_stack]:
for rec in strategy(formation):
all_needed.add(rec.agent_type)
gaps = all_needed - set(existing_agents)
recommendations = []
for agent_type in gaps:
recommendations.append(AgentRecommendation(
agent_type=agent_type,
source_strategy="gap-analysis",
source_entity="coverage-gap",
priority=self._gap_urgency(agent_type, formation),
template_config=self.get_template(agent_type),
))
return recommendations
Gap analysis takes the union of all recommendations from the other three strategies, compares it against your existing agent roster, and surfaces the holes. If your org runs Kubernetes across 12 services but you have no DevOps agent, gap analysis catches that.
The gap urgency score factors in how many discovery signals point to the missing agent type. A gap that shows up in team-based, service-based, and tech-stack strategies simultaneously gets a higher urgency score than one that only appears in one strategy.
Deduplication and Priority Merging
Four strategies running independently will produce duplicates. Your payments team maps to a backend-lead agent (team strategy). Your payment service maps to a backend-lead agent (service strategy). Your Python codebase maps to a backend-agent (tech strategy). That's three recommendations for overlapping coverage.
The deduplication layer merges by agent type:
def deduplicate(self, recommendations: list[AgentRecommendation]) -> list[AgentRecommendation]:
by_type: dict[str, list[AgentRecommendation]] = defaultdict(list)
for rec in recommendations:
by_type[rec.agent_type].append(rec)
merged = []
for agent_type, recs in by_type.items():
best = max(recs, key=lambda r: r.priority)
best.contributing_strategies = [r.source_strategy for r in recs]
best.merged_priority = sum(r.priority for r in recs) / len(recs)
merged.append(best)
return sorted(merged, key=lambda r: r.merged_priority, reverse=True)
Merged priority is the average across all contributing strategies. An agent type recommended by three strategies with scores of 8, 6, and 7 gets a merged priority of 7.0 — higher than one recommended by a single strategy with a score of 7.5. The logic: convergent signals from independent strategies are more reliable than a strong signal from a single source.
The output is a single ranked list. No duplicates. Clear priority ordering. Each recommendation carries metadata about which strategies contributed to it, so you can inspect the reasoning.
CLAUDE.md Template Mappings
Every recommended agent type maps to a CLAUDE.md template — the configuration file that defines an agent's role, tools, and behavior.
TEMPLATE_REGISTRY = {
"backend-lead": {
"role": "Backend Engineering Lead",
"tools": ["code-review", "api-design", "database-query", "test-runner"],
"claude_md_template": "templates/backend-lead.md",
"default_model": "claude-sonnet-4-20250514",
},
"frontend-agent": {
"role": "Frontend Specialist",
"tools": ["browser-test", "component-audit", "accessibility-check"],
"claude_md_template": "templates/frontend-agent.md",
"default_model": "claude-sonnet-4-20250514",
},
"devops-agent": {
"role": "DevOps Engineer",
"tools": ["k8s-manage", "terraform-plan", "monitoring-query"],
"claude_md_template": "templates/devops-agent.md",
"default_model": "claude-sonnet-4-20250514",
},
# ... more templates
}
When you provision a recommended agent, the system pulls the template, fills in org-specific context from the discovery data, and creates a ready-to-run agent. The backend-lead agent for your payments team gets a CLAUDE.md that references your actual payment service, your team's Slack channel, and your deployment pipeline — all pulled from the enterprise formation.
MCP Tools and API
Two interfaces expose the recommender: MCP tools for agent-to-agent use, and REST endpoints for dashboards and external systems.
MCP Tools
@mcp_tool("discovery_recommend_agents")
async def recommend_agents(org_id: str, include_gaps: bool = True) -> RecommendationSet:
"""Analyze enterprise formation and return ranked agent recommendations."""
formation = await discovery_engine.get_formation(org_id)
existing = await agent_registry.list_agents(org_id)
return recommender.recommend(formation, existing, include_gaps=include_gaps)
@mcp_tool("discovery_provision_recommended")
async def provision_recommended(org_id: str, agent_type: str) -> ProvisionResult:
"""Provision a recommended agent type with its template config."""
rec = await recommender.get_recommendation(org_id, agent_type)
return await provisioner.create_agent(org_id, rec.template_config)
Any agent in your fleet can call discovery_recommend_agents to get recommendations, then call discovery_provision_recommended to spin up the ones that make sense. A CTO agent reviewing organizational coverage can do this autonomously — discover gaps, recommend agents, provision them — without a human clicking through a dashboard.
REST API
GET /{org_id}/discovery/recommended-agents
Returns the full recommendation set as JSON. Query parameters let you filter by strategy, minimum priority threshold, or specific agent types. The response includes all metadata — contributing strategies, priority scores, template configs — so a frontend can render it as a reviewable list with one-click provisioning buttons.
Testing
56 unit tests cover the full surface:
- Strategy tests — each of the four strategies tested independently with realistic formations
- Deduplication tests — duplicate handling, priority merging, strategy attribution
- Priority scoring — boundary conditions, zero-activity teams, single-contributor repos
- Serialization — JSON round-trip for all recommendation types
- Edge cases — empty formations, no teams, no services, all agents already provisioned, single-strategy results
All 56 pass. The strategy tests use fixture formations that mirror real enterprise structures — not toy examples with two teams and one service, but formations with overlapping teams, polyglot tech stacks, and services that cross team boundaries.
Why This Matters
The recommender closes the loop between discovery and action. Before, Discovery Engine told you what your org looked like. Now it tells you what to do about it.
For a team evaluating agent deployment, the recommender answers the first question everyone asks: "Which agents should we set up?" Instead of guessing or copying a generic template, you get recommendations grounded in your actual organizational structure — your teams, your services, your tech stack, your gaps.
And because it plugs into the provisioning system, the path from "recommended" to "running" is one API call. No manual config. No template hunting. Discovery scans your org, the recommender analyzes the results, and you provision with a click.
That is the full cycle: scan, analyze, recommend, provision. Automatic. Grounded in data. And it keeps up as your org changes — rerun discovery, get updated recommendations, fill new gaps.
The Discovery Engine, the Agent Recommender, and the provisioning pipeline are live -- scan, analyze, recommend, provision. Build your own cyborgenic organization at agent.ceo.