From Ad-Hoc Prompts to Repeatable AI Systems
Most developers enter AI-assisted development through a prompt: open GitHub Copilot, ask a natural-language question, and hope the output is usable. That works for simple code suggestions, but collaborative and complex work demands more than improvisation. A three-part framework — structured prompts, agentic primitives, and context engineering — turns ad-hoc experimentation into an engineering discipline. The result is AI systems that code independently and do so reliably, predictably, and consistently.
The core idea is that agentic primitives — reusable, configurable building blocks — give agents clear instructions and capabilities, while context engineering ensures they always focus on the right information rather than simply more of it.
Layer 1: Structured Prompting with Markdown
Prompt quality directly determines output quality. Markdown provides a natural structure — headers, lists, links — that guides an AI's reasoning and makes outputs more predictable. Several techniques leverage Markdown for strategic prompt engineering:
- Context loading: Links such as
[Review existing patterns](./src/patterns/)act as context injection points, pulling relevant information from files or websites. - Structured thinking: Headers and bullets create clear reasoning pathways for the AI to follow.
- Role activation: Phrases like "You are an expert [in this role]" trigger specialized knowledge domains.
- Tool integration: Directives such as Use MCP tool
tool-nameenable controlled, repeatable code execution on MCP servers. - Precise language: Specific instructions eliminate ambiguity.
- Validation gates: Instructions to "Stop and get user approval" preserve human oversight at critical points.
Instead of telling the AI to Find and fix the bug, a structured prompt that specifies the file, symptoms, expected behavior, and approval gate yields far more consistent results.
Manually crafting perfect prompts for every task doesn't scale. The solution is to convert prompt-engineering insights into reusable, configurable systems.
Layer 2: Agentic Primitives as Building Blocks
A core agent primitive is a simple, reusable file or module that provides a specific capability or rule for an agent. Common examples include:
- Instructions files: Modular
.instructions.mdfiles with targeted scope provide structured guidance. GitHub's custom instructions feature gives Copilot repository-specific preferences via this pattern. - Chat modes:
.chatmode.mdfiles deploy role-based expertise with MCP tool boundaries that prevent cross-domain interference and security breaches. This enforces professional separation — architects don't build, engineers don't plan. - Agentic workflows:
.prompt.mdfiles carry reusable prompts with built-in validation. - Specification files:
.spec.mdfiles create implementation-ready blueprints that produce repeatable results whether executed by a person or AI. - Agent memory files:
.memory.mdfiles preserve knowledge and decisions across sessions. - Context helper files:
.context.mdfiles optimize information retrieval.
The pattern is clear: an ad-hoc request becomes a systematic workflow with explicit handoff points, automatic context loading, and validation. Each iteration on these files makes the agent more reliable and consistent through a structured, repeatable approach rather than trial and error.
Layer 3: Context Engineering for Focused Agents
LLMs, like people, have finite context windows and can be forgetful. Strategic context management helps agents focus on what's relevant, preserves context-window space, and improves reliability. Key techniques include:
- Session splitting: Use separate agent sessions for planning, implementation, and testing. A fresh context window improves focus for complex tasks.
- Modular rules: Apply only relevant instructions via
.instructions.mdfiles withapplyToYAML frontmatter syntax. This conserves context for actual work and reduces irrelevant suggestions. - Memory-driven development: Use
.memory.mdfiles to retain project knowledge across sessions. - Context optimization: Deploy
.context.mdhelper files to speed up retrieval and reduce cognitive load. - Cognitive focus: Chat modes in
.chatmode.mdfiles keep attention on relevant domains, reducing context pollution for more consistent outputs.
Agentic Workflows in Action
The three layers combine into agentic workflows — complete processes where primitives coordinate, prompts are understood, and only needed context is used. These workflows are implemented as .prompt.md files that orchestrate multiple primitives. They run locally in an IDE, in a terminal, or in CI pipelines.
Scaling with Tooling Infrastructure
Agentic primitives are natural-language executable software, and they need the same infrastructure as any programming ecosystem. JavaScript evolved from browser scripts to require runtimes, package managers, and deployment tooling; .prompt.md and .instructions.md files need the same support. These files exhibit modularity, reusability, dependencies, evolution, and distribution — the qualities of real software — and require corresponding infrastructure.
Agent CLI Runtimes
Most developers start building primitives directly in VS Code with GitHub Copilot, which suits interactive development and debugging. Moving beyond the editor — automating, scheduling, or integrating workflows — requires agent CLI runtimes like GitHub Copilot CLI in public preview. These runtimes execute primitives from the command line, tap advanced model capabilities, and unlock automation, scaling, and production integration.
Runtime Management
Teams that want to share, version, or productize their primitives may hit complexity managing multiple vendor CLIs with different installation procedures, configuration needs, and compatibility matrices. APM (Agent Package Manager) addresses this with unified runtime management and package distribution. It handles installation and configuration behind the scenes, so daily development in VS Code stays unchanged, workflows run regardless of the installed runtime, and the same apm run command works consistently across all runtimes.
Agents as Packaged Software
Agent primitives—custom instructions, prompts, and chat modes—behave a lot like traditional code once you want to share them with a team or push them into production. You start needing package management, dependency resolution, and version control.
Raw .md files get unwieldy fast when other people need the same MCP servers and compatible runtimes. APM supplies that missing layer. It doesn't replace your VS Code workflow; it wraps your agent primitives into distributable packages with dependencies, configuration, and runtime constraints, in the same way npm packages code.
Defining a Project
The apm.yml file acts as the package.json for your AI assets, declaring scripts, MCP dependencies, and input parameters:
# apm.yml - Project configuration (like package.json)
name: security-review-workflow
version: 1.2.0
description: Comprehensive security review process with GitHub integration
scripts:
copilot-sec-review: "copilot --log-level all --log-dir copilot-logs --allow-all-tools -p security-review.prompt.md"
codex-sec-review: "codex security-review.prompt.md"
copilot-debug: "copilot --log-level all --log-dir copilot-logs --allow-all-tools -p security-review.prompt.md"
dependencies:
mcp:
- ghcr.io/github/github-mcp-server
Running in CI/CD
Packaged primitives can drop straight into standard pipelines. The APM GitHub Action deploys a project with multi-runtime flexibility, using scripts to switch between agents or analysis types:
# .github/workflows/security-review.yml
name: AI Security Review Pipeline
on:
pull_request:
types: [opened, synchronize]
jobs:
security-analysis:
runs-on: ubuntu-latest
strategy:
matrix:
# Maps to apm.yml scripts
script: [copilot-sec-review, codex-sec-review, copilot-debug]
permissions:
models: read
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Run Security Review (${{ matrix.script }})
uses: danielmeppiel/action-apm-cli@v1
with:
script: ${{ matrix.script }}
parameters: |
{
"pr_id": "${{ github.event.pull_request.number }}"
}
env:
GITHUB_COPILOT_PAT: ${{ secrets.COPILOT_CLI_PAT }}
The matrix.script values (copilot-sec-review, codex-sec-review, copilot-debug) map exactly to the scripts defined in apm.yml. The action handles installing MCP dependencies like ghcr.io/github/github-mcp-server and passes parameters (such as pr_id) into the target .prompt.md workflow. The payoff is that these workflows run automatically with reproducible behavior, no manual triggers, and full CI visibility—no different from running a linter or a test suite.
Following the Ecosystem Playbook
This tooling progression mirrors the lifecycle of every successful programming ecosystem. The stages are:
- Raw code — agent primitives in
.prompt.mdand.instructions.mdfiles. - Runtime environments — agent CLI runtimes that execute them.
- Package management — APM as the distribution and orchestration layer.
- Thriving ecosystem — shared libraries and community packages built on that infrastructure.
what began as isolated Markdown files becomes a systematic software practice with the same packaging, distribution, and deployment discipline used for conventional applications.
Building Blocks: From Instructions to Workflows
Getting started means assembling four primitives into a coherent system: instructions, chat modes, reusable prompts, and specification templates.
Instruction Architecture
Instructions establish reliable default behavior without polluting every conversation with repetitive context. The design principle is modularity: rather than one giant file applied globally, you create targeted files that activate only for specific codebases or file types.
Practical steps include placing general rules in a repository-level copilot-instructions.md, then splitting domain rules into .instructions.md files under .github/instructions/. Use applyTo glob patterns to scope them narrowly:
.github/
├── copilot-instructions.md # Global repository rules
└── instructions/
├── frontend.instructions.md # applyTo: "**/*.{jsx,tsx,css}"
├── backend.instructions.md # applyTo: "**/*.{py,go,java}"
└── testing.instructions.md # applyTo: "**/test/**"
A frontend example shows how to constrain scope and behavior:
---
applyTo: "**/*.{ts,tsx}"
description: "TypeScript development guidelines with context engineering"
---
# TypeScript Development Guidelines
## Context Loading
Review [project conventions](../docs/conventions.md) and
[type definitions](../types/index.ts) before starting.
## Deterministic Requirements
- Use strict TypeScript configuration
- Implement error boundaries for React components
- Apply ESLint TypeScript rules consistently
## Structured Output
Generate code with:
- [ ] JSDoc comments for all public APIs
- [ ] Unit tests in `__tests__/` directory
- [ ] Type exports in appropriate index files
Chat Mode Boundaries
Chat modes enforce professional boundaries by domain. They operate like licensing: an architect can plan a bridge, but they should not build it themselves. This involves defining domain-specific rules with MCP tool access limits, tech stack knowledge scoped per mode, and specifying what LLM models are appropriate. Configuration comes from files like backend-engineer.chatmode.md:
| 💡 Security through MCP tool boundaries: Each chat mode receives only the specific MCP tools needed for their domain. Giving each chat mode only the tools it needs keeps your AI workflows safe, organized, and professionally separated—just like real-world roles and permissions. |
The practical boundary patterns cover common roles:
- Architect mode: Research tools only—no destructive commands or production code changes.
- Frontend engineer mode: UI tools only—no database or backend access.
- Backend engineer: API and database tools only—no UI or frontend changes.
- Technical writer: Documentation only—no code execution or sensitive system access.
---
description: 'Backend development specialist with security focus'
tools: ['changes', 'codebase', 'editFiles', 'runCommands', 'runTasks',
'search', 'problems', 'testFailure', 'terminalLastCommand']
model: Claude Sonnet 4
---
You are a backend development specialist focused on secure API development, database design, and server-side architecture. You prioritize security-first design patterns and comprehensive testing strategies.
## Domain Expertise
- RESTful API design and implementation
- Database schema design and optimization
- Authentication and authorization systems
- Server security and performance optimization
You master the backend of this project thanks to you having read all [the backend docs](../../docs/backend).
## Tool Boundaries
- **CAN**: Modify backend code, run server commands, execute tests
- **CANNOT**: Modify client-side assets
Agentic Workflows
Workflows orchestrate your primitives into repeatable processes, implemented as structured .prompt.md files. Designed well, they can run locally or be handed to an independent agent. Crucially, they include mandatory human reviews and explicit validation gates. A full example using feature-spec.prompt.md demonstrates the pattern:
---
mode: agent
model: gpt-4
tools: ['file-search', 'semantic-search', 'github']
description: 'Feature implementation workflow with validation gates'
---
# Feature Implementation from Specification
## Context Loading Phase
1. Review [project specification](${specFile})
2. Analyze [existing codebase patterns](./src/patterns/)
3. Check [API documentation](./docs/api.md)
## Deterministic Execution
Use semantic search to find similar implementations
Use file search to locate test patterns: `**/*.test.{js,ts}`
## Structured Output Requirements
Create implementation with:
- [ ] Feature code in appropriate module
- [ ] Comprehensive unit tests (>90% coverage)
- [ ] Integration tests for API endpoints
- [ ] Documentation updates
## Human Validation Gate
🚨 **STOP**: Review implementation plan before proceeding to code generation.
Confirm: Architecture alignment, test strategy, and breaking change impact.
Specification Templates
Templates close the gap between planning a feature and implementing it. They standardize documentation so a developer or agent can take a specification and build reliably. Each spec intends to define the problem, approach, components, validation criteria, and a handoff checklist. This makes the transition deterministic rather than interpretive.
Spec-kit implements this workflow directly, generating a spec (spec.md), an implementation plan (plan.md), and split tasks (tasks.md) ready for assignment. The gate is simple: specifications are not ready to delegate until they are broken into implementation-ready tasks.
From Principles to Practice
The concepts above only create value once they're embedded in your daily tooling. A pragmatic path forward starts with a small set of configuration files and builds outward incrementally.
Start with Global Instructions
Begin by creating a .github/copilot-instructions.md file in your repository. This is your "global rules" layer of context engineering — a single place to define project-wide conventions, coding standards, and behavioral expectations that apply to every interaction with Copilot. It's the cheapest way to make all subsequent AI interactions consistent.
Layer in Domain-Specific Guidance
Next, add .instructions.md files at the directory level for those parts of your codebase that need specialized knowledge. Use applyTo patterns to scope these files to relevant globs or paths. When Copilot operates within those directories, it loads the local context selectively instead of forcing everything through the global file, keeping token usage focused and relevant.
Follow that with custom chat modes tailored to your stack's domains. Where instructions files provide rules, chat modes provide boundaries — defining when a particular style of interaction should engage. Set up modes for your framework, your data layer, and your test strategy so that conversational context stays tightly scoped.
Build Your First Agentic Workflow
Once those layers are in place, author a .prompt.md file to create your first reusable agentic workflow. This file should encode a repeatable sequence of steps for a task class your team performs often — encoding the primitive trajectory you've designed. Turn that workflow into a composable capability distinct from an ad-hoc prompt.
Adopt Spec-Driven Development
Move from purely conversational AI work to artifacts by building a .spec.md template for feature specifications. The spec-kit project is a useful reference for this pattern. The goal is to make specifications first-class outputs, not ephemeral messages.
Now your workflow becomes strictly sequential and predictable:
- Write the technical implementation plan, defining the full scope of the change.
- Split the work into tasks — units small enough for one focused context session.
- Execute each task in its own session, carrying only the focused context it needs.
This sequence combined with your primitives and layered context files, makes agentic behavior something your team can rely on — task by task, session by session. If you're ready to push delegation even further, GitHub Copilot CLI provides a natural next step for coordinating multi-agent work directly from your command line.



