How We Tamed AI Output with a Three‑Layer Architecture for Android Code Migration to KMP
This article details how we used a three‑layer AI architecture—Skill for stable execution, SubAgent for context‑aware scheduling, and Agent Team for parallel collaboration—to reliably migrate a large Android codebase to a Kotlin Multiplatform project, addressing instability, context inflation, and efficiency challenges.
Background and Challenges
When migrating a massive Android codebase to a Kotlin Multiplatform (KMP) project, the key difficulty was not whether migration was possible but whether it could be done reliably. A single page migration touches UI, layout, business logic, and resources, creating tangled dependencies that surface as compilation errors if any step is missed. Manual file‑by‑file work is slow and error‑prone, while letting AI generate code directly often yields code that looks runnable but fails when integrated.
Early attempts to let AI handle the migration revealed three recurring problems:
Inconsistent results for the same operation – AI re‑interprets the task each time, causing output drift.
Increasing hallucinations with task complexity – As a page involves dozens of files, AI begins to invent non‑existent methods.
No mechanism for parallel processing – UI, layout, and business logic could be processed concurrently, but a single chat window forces serial execution.
These issues motivated the three‑layer solution: Skill, SubAgent, and Agent Team.
Three‑Layer Solution Overview
The architecture combines three complementary components:
Skill – Handles atomic execution and guarantees stable output.
SubAgent – Manages scheduling and prevents context‑inflation.
Agent Team – Enables parallel collaboration across independent tasks.
Both migration phases—extraction and conversion—use this stack. In the extraction phase, Agent Team runs four parallel workers (UI, layout, business logic, resources). In the conversion phase, SubAgent serially drives the steps: module generation → resource conversion → business‑code migration → UI conversion, with each step passing key artifacts via a shared Memory file. Every node’s stability is ensured by Skill.
Skill: Stabilizing Repetitive Tasks
Instability was first blamed on prompt quality, but the real cause was AI re‑interpreting the same task each time. Skill solves this by encapsulating a task’s execution logic in a reusable specification file that AI follows without maintaining conversation history. The specification is stateless and guarantees consistent output.
The most effective constraint added to a Skill is a Checklist —a list of granular steps that must be checked off. This reduces the AI’s tendency to skip steps in multi‑step tasks. Additionally, separating core rules into a main file and edge‑case handling into a references directory keeps the specification concise and focused.
For code extraction, the original monolithic Skill was split into three independent Skills:
extractor – Scans dependencies from entry calls and produces an initial extraction bundle.
validator – Independently checks the bundle for missing pieces, focusing on what is still needed rather than what was already extracted.
fixer – Addresses only the gaps identified by the validator.
This separation allows each layer to be evaluated in isolation, making debugging faster and improving overall reliability. The same “extract → validate → fix” pattern was later reused in the conversion stage (converter → validator → fixer).
SubAgent: Controlling Context Inflation
When a single dialog handled an entire page migration, early steps succeeded but later steps produced hallucinations—e.g., references to non‑existent methods or mismatched resource IDs. The root cause was context inflation: as more files were loaded, the AI’s memory of earlier information degraded.
SubAgent mitigates this by breaking a long‑chain task into discrete steps, each handled by an isolated SubAgent with its own context. To preserve information across steps, a structured Agent‑Memory file is written after each SubAgent finishes. Subsequent SubAgents read only the essential structured data (e.g., resource‑ID maps, module configurations) rather than the raw conversation history, preventing noise and further inflation.
An example: after the resource‑conversion SubAgent finishes, it writes a resource‑ID mapping file. The UI‑conversion SubAgent reads this file to resolve resource references accurately, avoiding hallucinated IDs.
Key insight: Memory files must contain distilled, consumable information, not a verbatim dump of chat logs.
Agent Team: Parallel Extraction for Speed and Quality
Even after solving context inflation, serial processing remained a bottleneck. Extracting a page involves four independent file types—UI components, layout files, business logic, and resources—none of which have strong inter‑dependencies. Running them serially adds their durations together and forces a single SubAgent to juggle multiple contexts.
Agent Team assigns each file type to a dedicated “Teammate” that runs in parallel, each with its own isolated context and deep expertise in its domain. Coordination between teammates occurs via a Mailbox message channel, allowing real‑time notifications of cross‑type dependencies (e.g., a Dialog discovered by the UI teammate that requires a layout teammate to add a corresponding file).
The result: total runtime approximates the longest individual path rather than the sum of all four, and the focused specialization improves extraction quality because each teammate can build richer dependency models for its file type.
Key Takeaways
Skills emerge from real‑world errors; they are not pre‑planned but iteratively refined as failure patterns surface.
Context inflation reaches a critical point earlier than expected; proactive task splitting is more cost‑effective than fixing hallucinations after they appear.
Memory files should convey only the structured information needed for subsequent steps, not raw dialogue.
Parallelism yields benefits beyond speed—specialized focus raises the quality of each task.
The decision rule for choosing between SubAgent (serial) and Agent Team (parallel) is simple: if tasks have strong dependencies, use SubAgent; otherwise, use Agent Team.
Further Reading
Related articles explore AI‑driven end‑to‑end development, runtime harnesses for agents, and practical guides to AI coding.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
