Welcome to Chapter 7, the final chapter of our beginner's guide!
In Chapter 6: Context Forking Mechanism, we learned how agents can clone themselves to multitask. In previous chapters, we learned how to define agents in Chapter 1 and store their memories in Chapter 5.
By now, your system might be swarming with agents: built-in ones, custom ones you wrote, and ones your team committed to the project repo.
This creates a new problem: Clutter and Confusion.
In this chapter, we will explore the Agent Presentation Layer.
Imagine you have a contact named "Mom" in your phone.
When "Mom" calls, you don't want to see three identical entries. You want your phone to merge them into one coherent profile and perhaps give it a special ringtone.
In AgentTool, you might have a generic "Sherlock" agent in your global user settings, but your current project has a specialized "Sherlock" agent designed for this specific codebase.
When you type @Sherlock, which one answers? How do you know?
We want to achieve two things in the User Interface (CLI):
The Presentation Layer acts like the "Contacts App" on your phone. It handles three jobs:
It organizes agents based on where they live (User Settings vs. Project Settings vs. Built-in).
It enforces a hierarchy. A "Project Agent" usually beats a "User Agent." If both exist with the same name, the lower-priority one is marked as overridden.
It assigns consistent colors (like Red for specific sub-agents or Blue for the main assistant) so the chat log is readable.
When you run the command claude agents or list them in the UI, the system doesn't just dump a raw list. It processes them.
The Input (Raw Data):
Sherlock (Source: User)Sherlock (Source: Project)Plan (Source: Built-in)The Presentation Layer Logic:
Project Sherlock shadows User Sherlock.The Output (What you see):
PROJECT AGENTS
โ Sherlock (Purple) - Specialized Investigator
USER AGENTS
โ Sherlock (Greyed out) - Overridden by Project Settings
BUILT-IN AGENTS
โ Plan (Green) - The Architect
How does the code decide who wins? Let's look at the flow.
Let's look at the actual code that powers this logic. We will look at agentDisplay.ts and agentColorManager.ts.
First, we need to know the "Rank" of our sources. This list defines the order in which agents are displayed.
From agentDisplay.ts:
// simplified from agentDisplay.ts
export const AGENT_SOURCE_GROUPS = [
{ label: 'User agents', source: 'userSettings' },
{ label: 'Project agents', source: 'projectSettings' },
{ label: 'Local agents', source: 'localSettings' },
// ...
{ label: 'Built-in agents', source: 'built-in' },
]
Explanation: This array acts as the table of contents. When rendering the list, the UI loops through these groups. "User agents" appear at the top, "Built-in agents" at the bottom.
This is the most critical function. It compares the "All Agents" list against the "Active Agents" list to see who didn't make the cut.
From agentDisplay.ts:
// simplified from agentDisplay.ts
export function resolveAgentOverrides(
allAgents: AgentDefinition[],
activeAgents: AgentDefinition[],
): ResolvedAgent[] {
// 1. Create a map of the winners (Active agents)
const activeMap = new Map(activeAgents.map(a => [a.agentType, a]))
const resolved = []
// 2. Check every available agent
for (const agent of allAgents) {
const active = activeMap.get(agent.agentType)
// 3. If active source is different, this agent is overridden
const overriddenBy = (active && active.source !== agent.source)
? active.source
: undefined
resolved.push({ ...agent, overriddenBy })
}
return resolved
}
Explanation:
activeAgents (the ones that the Runtime will actually use).allAgents (every file found on disk).Sherlock in allAgents (User source), but the active Sherlock is from the Project source, we flag the User one as overriddenBy: 'project'.Finally, to make the chat readable, we map agent names to specific colors.
From agentColorManager.ts:
// simplified from agentColorManager.ts
export const AGENT_COLORS = [
'red', 'blue', 'green', 'yellow', 'purple', ...
] as const
export function getAgentColor(agentType: string) {
// 1. General Purpose agent is usually uncolored (default text)
if (agentType === 'general-purpose') return undefined
// 2. Check the in-memory map for assigned colors
const agentColorMap = getAgentColorMap()
const existingColor = agentColorMap.get(agentType)
// 3. Convert simple color name to Theme color
if (existingColor) {
return AGENT_COLOR_TO_THEME_COLOR[existingColor]
}
}
Explanation:
Sherlock -> Purple).In this final chapter, we learned about the Agent Presentation Layer.
Congratulations! You have completed the AgentTool architecture tutorial. You now understand the full lifecycle of an AI Agent:
You are now ready to dig into the codebase and build your own custom agents! Happy coding!
Generated by Code IQ