Last Week

The home screen implementation is complete with responsive design supporting everything from portrait phones to landscape tablets. Dark mode works beautifully – a telltale sign of an app “written with love.” All UI work was done in isolation with mock data, keeping the presentation layer pure until the backend integration is ready.

The Context Window Crisis

Working with Claude Code revealed a fundamental limitation of AI-assisted development: the 128,000 token context window. Every piece of research, every line of generated code, every test output – it all accumulates in the context until the system hits 80% capacity and demands compaction.

Context compaction is lossy compression for AI memory. The system attempts to summarize and retain what it thinks will be needed, but critical details about syntax, best practices, and architectural decisions often get lost. The result? Significant quality degradation and the dreaded “You’re absolutely right” responses when correcting mistakes the AI wouldn’t have made with full context.

What does it mean in English?

Imagine working with a brilliant assistant who can only remember about 100 pages of information at once. When their notebook fills up, they have to summarize everything into 20 pages before continuing. Important details get lost in the summary, and suddenly they’re making mistakes they wouldn’t have made before. Subagents solve this by giving you multiple assistants, each with their own fresh 100-page notebook, specialized for specific tasks.

Nerdy Details

Understanding the Context Window Problem

The Claude Opus model provides 128,000 tokens (roughly equivalent to words, though not exactly). Here’s how quickly that fills up:

// Single feature implementation might include:
// 1. Research phase (10,000-20,000 tokens)
- Library documentation pages
- Stack Overflow solutions
- Best practice guides

// 2. Implementation phase (15,000-30,000 tokens)
- Generated view model (2,000 tokens)
- Generated UI components (5,000 tokens)
- Generated tests (8,000 tokens)
- Repository layer updates (3,000 tokens)

// 3. Debugging phase (40,000+ tokens easily)
- Test output logs (10,000+ tokens per run)
- Stack traces (2,000 tokens each)
- Gradle build outputs (5,000+ tokens)

// Total: Already approaching 80,000-100,000 tokens

Claude Code enforces a hard stop at ~102,400 tokens (80% of 128K) to leave room for responses:

# Simplified context management logic
class ContextManager:
    MAX_TOKENS = 128000
    SAFETY_THRESHOLD = 0.8
    
    def check_context(self, current_tokens: int) -> bool:
        if current_tokens >= self.MAX_TOKENS * self.SAFETY_THRESHOLD:
            raise ContextWindowExceeded(
                f"Context at {current_tokens} tokens. "
                f"Compaction required before continuing."
            )
        return True

The Compaction Problem Illustrated

When compaction occurs, the AI attempts intelligent summarization:

// Original context (before compaction):
"""
Research findings:
- Voyager navigation library uses Screen interface
- Each screen must override Content() composable
- Navigation state managed via LocalNavigator
- Important: Always use remember {} for navigation operations
- Testing requires MockNavigator with specific setup
- Dark mode requires MaterialTheme wrapper with custom colors

Implementation details:
- HomeScreen implements responsive grid layout
- LazyVerticalGrid for tablet, LazyColumn for phone
- WindowSizeClass determines layout strategy
- Dark mode colors: primary=#BB86FC, surface=#121212
- Animation specs: tween(300) for all transitions
"""

// After lossy compaction:
"""
Summary: Implemented home screen with Voyager navigation.
Used responsive layouts and dark mode support.
Some testing considerations noted.
"""

Critical implementation details vanish, leading to:

  • Incorrect API usage
  • Lost architectural decisions
  • Forgotten test requirements
  • Missing animation specifications

Enter Subagents: Fresh Context Windows On Demand

Subagents fundamentally change the game by providing isolated, specialized context windows:

// Master agent configuration
class MasterAgent(
    private val contextWindow: ContextWindow = ContextWindow(128000)
) {
    fun delegateToSubagent(task: Task): Result {
        // Each subagent gets a FRESH 128K context window
        val subagent = SubagentFactory.create(
            type = task.type,
            contextWindow = ContextWindow(128000), // New window!
            claudeMdFile = getSpecializedInstructions(task.type)
        )
        
        return subagent.execute(task)
    }
}

The Seven Subagents Architecture

Based on practical experience, here’s a battle-tested subagent organization:

# .claude/subagents.yaml

subagents:
  ui_designer:
    description: "Handles all UI/UX implementation"
    context_preserved:
      - Material Design guidelines
      - Responsive design patterns
      - Dark mode specifications
      - Animation timing functions
    trigger_phrases:
      - "implement screen"
      - "create component"
      - "responsive layout"
    
  test_enforcer:
    description: "Writes and debugs tests"
    context_preserved:
      - Test framework setup
      - Mocking strategies
      - Coverage requirements (95% domain)
      - Common test patterns
    trigger_phrases:
      - "write tests"
      - "debug test failure"
      - "coverage report"
    
  debugger:
    description: "Analyzes logs and stack traces"
    context_preserved:
      - Error patterns database
      - Common Kotlin/Gradle issues
      - Debugging strategies
    trigger_phrases:
      - "analyze error"
      - "debug issue"
      - "stack trace"
    
  git_operator:
    description: "Handles version control"
    context_preserved:
      - Commit message conventions
      - Branch strategy
      - PR templates
    trigger_phrases:
      - "commit changes"
      - "create PR"
      - "merge conflict"
    
  architect:
    description: "Ensures clean architecture"
    context_preserved:
      - Layer boundaries
      - Dependency rules
      - Design patterns
    trigger_phrases:
      - "architecture review"
      - "refactor for clean"
      - "dependency injection"
    
  researcher:
    description: "Library research and documentation"
    context_preserved:
      - Project dependencies
      - Version compatibility matrix
      - API documentation links
    trigger_phrases:
      - "research library"
      - "find solution"
      - "best practice"
    
  performance_optimizer:
    description: "Performance and optimization"
    context_preserved:
      - Baseline metrics
      - Optimization techniques
      - Profiling results
    trigger_phrases:
      - "optimize performance"
      - "reduce memory"
      - "improve speed"

Subagent Claude.md Files

Each subagent has specialized instructions:

# .claude/ui_designer_claude.md

You are a specialized UI implementation agent for a Kotlin Multiplatform app.

## Core Responsibilities
- Implement responsive layouts using WindowSizeClass
- Ensure dark mode compatibility
- Follow Material Design 3 guidelines
- Maintain 60fps animations

## Critical Rules
1. ALWAYS use LazyColumn/LazyGrid for lists
2. NEVER hardcode dimensions - use dp/sp appropriately
3. ALWAYS test on phone portrait, phone landscape, tablet
4. Dark mode colors must meet WCAG AA contrast ratios

## Layout Breakpoints
```kotlin
when (windowSizeClass.widthSizeClass) {
    WindowWidthSizeClass.Compact -> // Phone portrait
    WindowWidthSizeClass.Medium -> // Phone landscape/small tablet
    WindowWidthSizeClass.Expanded -> // Tablet/desktop
}

Animation Standards

  • Enter/Exit: 300ms tween
  • Shared element: 400ms spring
  • Loading states: 200ms fade

**Real-World Context Preservation Example**

Without subagents (single context):
```kotlin
// Early in conversation
"Implement home screen with responsive grid"
// AI reads Material Design docs, Grid layout guides (15K tokens)
// Generates implementation (5K tokens)

// Later, after more features...
"Add dark mode support"
// Context nearly full, must compact
// Material Design docs summarized to "use dark colors"
// Results in: backgroundColor = Color.Black // Wrong!

// Should have been:
backgroundColor = MaterialTheme.colorScheme.background // Correct

With subagents:

// Master agent
"Implement home screen with responsive grid"
// Delegates to ui_designer subagent

// ui_designer subagent (fresh context)
// Reads Material Design docs fully
// Implements correctly

// Later...
"Add dark mode support"
// Delegates to ui_designer subagent again

// ui_designer subagent (fresh context again!)
// Has full Material Design guidelines
// Implements correctly with proper theme colors

Measuring Subagent Effectiveness

// Metrics before subagents
data class DevelopmentMetrics(
    val contextCompactionsPerFeature: Float = 2.3f,
    val errorsAfterCompaction: Int = 5,
    val "you're absolutely right" responses: Int = 8,
    val manualFixesRequired: Int = 12,
    val timePerFeature: Duration = 4.hours
)

// Metrics after subagents
data class ImprovedMetrics(
    val contextCompactionsPerFeature: Float = 0.0f, // None!
    val errorsAfterCompaction: Int = 0,
    val "you're absolutely right" responses: Int = 1,
    val manualFixesRequired: Int = 2,
    val timePerFeature: Duration = 2.5.hours
)

Practical Subagent Invocation Patterns

# Explicit subagent summoning
"Use the test_enforcer agent to write comprehensive tests for HomeViewModel"

# Implicit delegation (master agent decides)
"Debug why the tests are failing with NullPointerException"
# Master recognizes this needs debugger subagent

# Multi-agent workflow
"Implement the dashboard screen with tests and commit the changes"
# Master orchestrates:
# 1. ui_designer -> implements screen
# 2. test_enforcer -> writes tests  
# 3. git_operator -> commits with proper message

Advanced Subagent Communication

The master agent aggregates subagent results:

class MasterAgent {
    suspend fun implementFeature(request: FeatureRequest): FeatureResult {
        val tasks = planTasks(request)
        
        val results = tasks.map { task ->
            when (task.type) {
                TaskType.UI -> uiDesignerAgent.execute(task)
                TaskType.TEST -> testEnforcerAgent.execute(task)
                TaskType.DEBUG -> debuggerAgent.execute(task)
                else -> executeLocally(task)
            }
        }
        
        return FeatureResult(
            code = results.filterIsInstance<CodeResult>(),
            tests = results.filterIsInstance<TestResult>(),
            documentation = aggregateDocumentation(results)
        )
    }
}

Subagent Context Window Optimization

Each subagent can be tuned for its specific needs:

# Debugger needs large context for logs
debugger:
  model: claude-3-opus  # 128K context
  token_allocation:
    input: 100000  # Large space for logs
    output: 28000

# Git operator needs minimal context  
git_operator:
  model: claude-3-haiku  # Smaller, faster model
  token_allocation:
    input: 10000
    output: 5000

Next Week

Focus shifts to connecting the beautiful UI to the backend reality. This means wiring up view models to the domain and data layers, replacing mock data with live Supabase queries. The subagent architecture will be crucial for managing the complexity of integration tests, state management debugging, and maintaining clean architecture boundaries across all layers.

The productivity gains from subagents have been transformative – from constant context battles to smooth, uninterrupted development flow.