Avoiding Monolithic AI Workflow Design in GitHub Copilot: Better Structure for Custom Agents, Instructions, and Skills
Honest disclaimer: The thoughts here are mine — the prose, structure, and general readability are courtesy of AI. I handed it a brain-dump and it handed back something you'd actually want to read. Felt appropriate, given the topic.
Most teams building agentic workflows skip the architecture work and jump straight into building. They don't think through the boundaries first—what orchestration owns, what each capability should do independently, where standards live. So the first agent they write becomes a dump for everything: orchestration, logic, policy, approval, output formatting. All in one. It works until it doesn't.
This post is about why that happens, what breaks when it does, and a practical architecture that scales: thin orchestrator agents, focused Skill units, clear Instructions, and predictable output paths. In GitHub Copilot (and similar agent harnesses), the goal is to keep orchestration, capabilities, and standards decoupled as systems scale. It's structured so you can reason about each part independently.
1. What goes wrong in monolithic agent design
When reviewing agentic setups in coding agent tools, the pattern that keeps breaking teams is the same: developers start building the first agent without deciding where boundaries should be. They write orchestration, capability logic, state management, and output formatting all into one prompt because they haven't yet figured out the architecture themselves.
The trap is that the first agent works. It delivers output, solves the immediate problem. There's no signal that you need architecture until the second workflow reveals the hidden coupling—the scoring logic is buried inside the first agent, the output format is baked into the prompt, the state management is scattered.
The result is that one large Custom agent ends up owning everything—and because the boundaries were never explicit, changing one piece quietly breaks another.
Here's the hard part: AI can help you flesh out and refine the architecture, but the hard thinking has to come first. You need to learn from a failure (or understand the pattern upfront), articulate where orchestration ends and capability logic begins, and define what your output contracts should be. The AI can expand what you tell it to write, but it can't extract the thinking you skipped. So teams often end up shipping the monolithic version anyway, then iterating frantically when it breaks.
In practice, most failures here are not model failures. They are boundary failures—the result of skipping the architecture phase.
Here's why no model improvement can fix a boundary failure: if data retrieval and interpretation live in the same agent, adding a new data source changes interpretation. You connect the agent to a new API for market data, and suddenly it starts weighting market signals differently in its reasoning. The model isn't broken—it's responding to a longer, more complex prompt. But the structural coupling means you can't improve one part without accidentally changing another. Restructuring is the only fix.
When too much responsibility lives in one agent, each change becomes risky and expensive. A fix in one area quietly changes behavior somewhere else because too much is tied together.
Key Characteristics:
- Coupled responsibilities: A single file mixes policy, execution logic, and artifact contracts.
- Low reusability: Valuable capability cannot be invoked independently by other workflows.
- High guardrail load: The prompt grows more defensive because the structure is doing too little.
Example: If scoring logic lives inline inside one agent, every workflow that needs scoring must re-run that whole workflow instead of invoking a reusable Skill.
2. Anti-patterns to avoid
These patterns are common in first-generation AI workflow repos and should be treated as structural debt.
| Anti-pattern | Why it fails over time |
|---|---|
| Monolithic Custom agent as the only execution unit | No modular reuse, hard to test, hard to evolve safely |
| Skills that contain specimen outputs instead of field contracts | Encourages copying examples instead of extracting real run data. Bad: "output: { score: 8.5, reason: "High quality PR", flags: ["needs-security-review"] }" Good: "output: { score: number(0-10), reason: string, flags: array<string> }" — typed, required fields, no fabricated content. |
| Inconsistent naming and dispatch conventions | Increases cognitive load and onboarding friction |
| Divergent output paths between producers and consumers | Breaks reuse checks and forces people to regenerate work they already had |
| Mixing analysis with generation/approval workflows in one utility | Bloats scope and creates unnecessary safety complexity |
3. Clear role boundaries: who should own what
Good structure starts by assigning one responsibility per layer and enforcing it.
Key Characteristics:
- Custom agent: Should primarily own orchestration (phase order, tool access, run policy, result handling).
- Skill: Should primarily own capability logic (inputs, steps, outputs, success criteria).
- Instructions: Should define standards (coding, naming, output conventions by
applyTo). - MCP server: A separate layer—skills call MCP servers to access external systems (runtime data, APIs, stores). MCP is not part of the orchestration/skill/instructions structure itself; it's how skills reach out.
Example: A workflow agent decides sequence and policy. It delegates extraction, scoring, and reporting to distinct Skill units. Each skill may call an MCP server to fetch data. Standards for output format and file layout remain in Instructions, not copied into every skill.
3.5. Boundary test: what goes where
When decisions don't fit neatly, use these tests:
Orchestrator: Logic that reads output from one skill to decide what to run next. Run-safety policy (approval gates, timeouts). Phase sequencing. Conditional branching based on prior results.
Skill: Logic that retries on transient failure. Domain-specific error handling (what makes output invalid for your use case). Calls to external systems via MCP. Capability-specific success criteria.
Instructions: Standards that apply across multiple workflows. File naming conventions. Output format requirements (JSON schema, field ordering). Code review style guides.
In doubt: if the decision is specific to one capability, it goes in the skill. If it orchestrates across capabilities, it goes in the orchestrator. If it's a standard all workflows follow, it goes in instructions.
4. The impact of getting the boundaries wrong
Bad boundaries do not stay contained inside agent files. They show up in team speed, review quality, and confidence in the workflow.
Common Impacts:
- Slower changes: Small fixes require editing large prompts or orchestration blocks, so safe iteration turns into careful, infrequent releases.
- Regression-heavy maintenance: The same file decides too many things at once, so bug fixes often change output structure, routing, or approval behavior by accident.
- Weak reuse: Teams rebuild the same extraction or scoring logic in multiple places because the useful part was never extracted into a reusable Skill.
- Noisy reviews: Reviewers end up parsing long prose blobs instead of inspecting a narrow capability contract or a specific orchestration decision.
- Harder incident response: When output quality drops, it is unclear whether the cause lives in instructions, tool access, orchestration order, or embedded business logic.
- Lower confidence: Once runs feel unpredictable, teams add more guardrail text instead of fixing structure, which usually makes the workflow harder to review and no more reliable.
Example: If one agent both pulls runtime data, interprets it, applies policy, and writes final artifacts, a bad result gives you nowhere obvious to start. The team cannot tell whether the failure came from data retrieval, capability logic, or orchestration policy without reading and re-running the whole thing.
5. Design principles that prevent drift
The difference between a stable system and a fragile one is usually a handful of explicit contracts.
- Contract-first skills: Define typed output fields and required inputs; avoid canned "example result" payloads in operational extraction prompts.
- Single output root per workflow family: Producers and consumers should resolve the same artifact paths.
- Consistent naming: Standardize file suffixes and dispatch style across all agents.
- Narrow utility scope: Keep analysis utilities analysis-only; split generation/approval into separate utilities.
- Policy in one place: Keep run-safety and orchestration policy in agents, not duplicated in every skill. When approval logic lives in both the extraction skill and the scoring skill, changes to approval criteria break both. Keep approval in the orchestrator instead.
6. A reference structure for mixed agent systems
This baseline layout keeps boundaries visible and enforceable.
.github/
agents/
workflow-orchestrator.agent.md # sequencing + policy only
skills/
capability-a/SKILL.md # one capability, one contract
capability-b/SKILL.md
instructions/
output-standards.instructions.md # applyTo: artifact paths, naming, schemas
copilot-instructions.md # global rules
.vscode/
mcp.json # external system connectors
documentation/
extracted/
<workflow-name>/ # single canonical output rootHow it works:
The orchestrator agent (workflow-orchestrator.agent.md) invokes skills by referencing them: "Use the extraction skill to pull requirements". Each skill file contains a full contract—inputs, output schema, success criteria. The orchestrator passes skill output to the next step by contract, not by example. If extraction outputs { requirements: string[], confidence: number }, that contract is defined once in the skill and referenced in instructions, not re-specified in every orchestrator prompt. Skills fetch runtime data via MCP servers in .vscode/mcp.json; the orchestrator never calls external APIs directly.
7. Migration approach that works in real teams
Do not big-bang this refactor. Extract capability by capability while preserving output contracts.
- Pull the highest-value inline logic into its own Skill first.
- Define output contracts explicitly before implementation—design the contract like you would an API in a distributed system. Inputs, output schema (required fields, types), success criteria. If you're extracting from a monolithic agent, run it on real data, capture actual outputs, and formalize those as contracts. The skill implementation follows the contract, not the other way around.
- Keep the Custom agent focused on orchestration as each extraction lands.
- Unify naming and output paths before adding new capabilities.
- Split non-core responsibilities into separate utilities once contracts are stable.
Wrapping Up
Most AI workflow fragility is self-inflicted architecture debt. The wrong structural decision does not just make prompts ugly; it slows work down, hides failure causes, and makes the whole system harder to trust. Keep Custom agents thin, Skill units explicit, and Instructions authoritative. Good boundaries do more for quality and safety than another page of guardrails.
Comments
Post a Comment