FAI Instructions Authoring
Create WAF-aligned coding standards with glob-based targeting.
What Instructions Do
Instructions are persistent, passive coding standards that Copilot absorbs automatically based on the files you're editing. You never invoke an instruction explicitly — instead, the applyTo glob pattern determines when it activates. When you open a Python file, every instruction with applyTo: "**/*.py" kicks in silently.
This makes instructions the most scalable primitive. Write a security instruction once, and every developer on the team gets the same guardrails applied to every file matching the pattern — without changing their workflow.
The .instructions.md Format
Every instruction file has two parts: YAML frontmatter (metadata) and Markdown body (the rules). The file must be named kebab-case.instructions.md and placed in .github/instructions/.
---description: "Python coding standards with WAF security and reliability"applyTo: "**/*.py"waf: - security - reliability - cost-optimization---
## Authentication- Use `DefaultAzureCredential` for all Azure SDK clients- Never hardcode connection strings, API keys, or tokens- Reference secrets via Key Vault: `SecretClient(vault_url, credential)`
## Error Handling- Wrap all external API calls with retry and exponential backoff- Use `tenacity`: `@retry(stop=stop_after_attempt(3), wait=wait_exponential())`- Log exceptions with correlation_id for distributed tracing
## Cost Controls- Set `max_tokens` on every OpenAI call (never leave unlimited)- Use gpt-4o-mini for classification, summarization, simple extraction- Reserve gpt-4o for multi-step reasoning and architecture decisions
## Observability- Use `structlog` with bound context (correlation_id, user_id, play_id)- Emit OpenTelemetry spans around LLM calls with token count attributesFrontmatter Fields
| Field | Required | Type | Validation |
|---|---|---|---|
| description | Yes | string | ≥ 10 characters |
| applyTo | Yes | string (glob) | Valid glob pattern |
| waf | Optional | string[] | Valid pillar names from the 6-pillar set |
Glob Pattern Reference
The applyTo field uses standard glob patterns. Here are the most common patterns for FAI instructions:
| Pattern | Matches | Use Case |
|---|---|---|
| **/*.py | All Python files | Python coding standards |
| **/*.{ts,tsx} | TypeScript + React | Frontend standards |
| **/*.bicep | Bicep IaC files | Infrastructure standards |
| **/*.{json,yaml,yml} | Config files | Config validation rules |
| src/api/**/*.py | API route files only | API-specific standards |
| **/test_*.py | Python test files | Testing conventions |
| **/* | Every file | Universal rules (use sparingly) |
Writing Effective Rules
Good instruction rules are specific, actionable, and include concrete code patterns. Avoid vague guidance like "write secure code." Instead, tell Copilot exactly what to do:
# ❌ Bad — vague, not actionable- Write secure code- Handle errors properly- Optimize for performance
# ✅ Good — specific, concrete, actionable- Use DefaultAzureCredential instead of connection strings- Wrap HTTP calls in @retry(stop=stop_after_attempt(3))- Cache embedding results in Redis with 24h TTL- Set max_tokens=1000 for standard queries, 4000 for complex
# ✅ Better — includes code patterns- Authentication pattern: ```python from azure.identity import DefaultAzureCredential credential = DefaultAzureCredential() client = OpenAIClient(endpoint, credential) ```Scope: Global vs File-Specific
FrootAI supports two instruction scopes:
- Global —
.github/copilot-instructions.mdapplies to every interaction regardless of file type. Use for project-wide conventions like naming, architecture patterns, and team preferences. - File-specific — Files in
.github/instructions/withapplyToglobs apply only when editing matching files. Use for language-specific or domain-specific standards.
Both scopes are additive. When editing a Python file, Copilot sees the global instructions plus all file-specific instructions matching **/*.py. All matching rules are active simultaneously — there is no conflict resolution.
WAF Pillar Alignment
The waf frontmatter field tags an instruction with architecture pillars. The FAI Engine can filter instructions by pillar, and play manifests auto-apply matching instructions based on context.waf.
---description: "Bicep infrastructure with WAF reliability and security"applyTo: "**/*.bicep"waf: - reliability - security - operational-excellence---
## Reliability- Deploy all services with zone redundancy where available- Use availability zones for AKS node pools and App Service plans- Configure health probes on every load-balanced endpoint
## Security- Enable managed identity on all compute resources- Use private endpoints for PaaS services (Storage, Cosmos DB, AI Search)- Assign least-privilege RBAC roles — never use Owner or Contributor
## Operational Excellence- Tag every resource: environment, team, cost-center, play- Enable diagnostic settings sending to Log Analytics workspace- Use Bicep modules from the verified infra-registry/Testing Instructions in VS Code
After writing an instruction, verify it works by testing in Copilot Chat:
# 1. Place your instruction filecp my-instruction.instructions.md .github/instructions/
# 2. Open a file matching the applyTo patterncode src/app.py # If applyTo: "**/*.py"
# 3. Ask Copilot a question that should trigger the rule# "How should I authenticate to Azure Storage?"# → Copilot should suggest DefaultAzureCredential (per your rule)
# 4. Validate with the primitives validatornpm run validate:primitives# ✅ instructions/my-instruction.instructions.md — valid# description: ✅ (>= 10 chars)# applyTo: ✅ (valid glob)# waf: ✅ (valid pillar names)Common Mistakes
| Mistake | Problem | Fix |
|---|---|---|
| Too many rules in one file | Exceeds context window | Split by concern (security, testing, API) |
| Vague guidance | Copilot ignores it | Use concrete code patterns |
| applyTo: "**/*" overuse | Unnecessary noise | Scope to specific file types |
| Missing description | Validation failure | Add ≥ 10 char description |
| Underscores in filename | Naming violation | Use lowercase-hyphen only |
Real-World: TypeScript Instruction
Here's a production-ready instruction for TypeScript projects with performance and security alignment:
---description: "TypeScript standards with WAF performance and security"applyTo: "**/*.{ts,tsx}"waf: - performance-efficiency - security---
## Type Safety- Enable strict mode in tsconfig.json (strict: true)- Avoid `any` type — use `unknown` with type guards instead- Define API response types explicitly, never infer from fetch
## Security- Sanitize all user input before rendering (DOMPurify for HTML)- Use parameterized queries for database operations- Never interpolate user input into SQL or shell commands
## Performance- Use React.memo() for expensive pure components- Lazy-load routes with React.lazy() and Suspense- Prefer server components for data fetching (Next.js App Router)- Debounce search inputs (300ms default)
## Imports- Use barrel exports sparingly — they defeat tree-shaking- Prefer direct imports: import { Button } from "@/components/ui/button"Scaffolding a New Instruction
Use the scaffold script to generate a properly structured instruction file:
# Scaffold a new instructionnode scripts/scaffold-primitive.js instruction
# Interactive prompts:# ? Instruction name (kebab-case): go-api-standards# ? Description: Go API coding standards with reliability WAF alignment# ? applyTo glob: **/*.go# ? WAF pillars: reliability, security## Created:# .github/instructions/go-api-standards.instructions.md
# Validatenpm run validate:primitives