The mission-control (Flight Control) project is being closed upstream. This embeds the project files directly in the repo under container/mission-control/, bakes them into the Docker image at /opt/mission-control, and copies them into place at container startup instead of git cloning from GitHub. Also adds missing osc52-clipboard, audio-shim, and triple-c-sso-refresh to the programmatic Docker build context in image.rs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9.7 KiB
Legs
Legs are the AI-optimized layer of Flight Control. They provide structured, explicit instructions that AI agents can execute without ambiguity.
What is a Leg?
A leg is a single, atomic unit of implementation work. Legs are:
- Explicit: No ambiguity about what "done" means
- Bounded: Clear start and end points
- Context-complete: All necessary information included
- AI-consumable: Structured for machine parsing
Leg vs. Flight vs. Mission
| Aspect | Mission | Flight | Leg |
|---|---|---|---|
| Scope | Outcome | Feature | Task |
| Duration | Days-weeks | Hours-days | Minutes-hours |
| Modifications | Allowed | Allowed | Create new instead |
| Audience | Humans | Developers/AI | AI agents |
Leg Structure
Legs follow a consistent structure optimized for AI consumption:
# Leg: {slug}
## Flight Link
[Parent flight](../flight.md)
## Objective
Single sentence describing what this leg accomplishes.
## Context
Information the AI needs to understand this task.
## Inputs
- What exists before this leg runs
## Outputs
- What exists after this leg completes
## Acceptance Criteria
- [ ] Criterion 1
- [ ] Criterion 2
- [ ] Criterion 3
## Verification Steps
How to confirm each criterion is met (commands, manual checks, tools).
## Implementation Guidance
Specific patterns, approaches, or constraints.
## Files Likely Affected
- `path/to/file.ts`
- `path/to/test.ts`
Writing Effective Legs
Objectives
State exactly what the leg accomplishes in one sentence:
Weak:
Set up the user stuff
Strong:
Create the User model with email, password_hash, and timestamps fields
The objective should be:
- Specific: Clear what will be created/modified
- Verifiable: Can confirm completion by inspection
- Atomic: One cohesive piece of work
Context
Provide information the AI needs but might not have:
## Context
This project uses Prisma for database access. The existing `prisma/schema.prisma`
file contains the Post and Comment models. User will be referenced by these
models via foreign keys.
Authentication uses JWT tokens. The password_hash field will store bcrypt hashes
(cost factor 12). The email field must be unique and will be used as the login
identifier.
Good context includes:
- Relevant technology/framework information
- Relationship to existing code
- Design decisions from the parent flight
- Constraints that affect implementation
Inputs and Outputs
Be explicit about state before and after:
## Inputs
- Prisma schema at `prisma/schema.prisma` with Post and Comment models
- No existing User model or authentication
## Outputs
- User model added to Prisma schema
- Migration file generated
- Migration applied to development database
Inputs help the AI understand starting conditions. Outputs define the expected end state.
Acceptance Criteria
Define exactly what "done" means:
## Acceptance Criteria
- [ ] User model exists in `prisma/schema.prisma`
- [ ] User model has fields: id, email, password_hash, created_at, updated_at
- [ ] email field has `@unique` attribute
- [ ] Migration file exists in `prisma/migrations/`
- [ ] `npx prisma migrate status` shows no pending migrations
- [ ] TypeScript types generated (`npx prisma generate` succeeds)
Acceptance criteria should be:
- Binary: Either met or not met
- Observable: Can verify by inspection or test
- Complete: Nothing else required for "done"
Verification Steps
Tell the AI exactly how to confirm each criterion:
## Verification Steps
- Run `npx prisma migrate status` — should show no pending migrations
- Run `npm test` — all tests pass
- Open browser to `/users` — page loads without errors
- Tab through form fields — focus order matches visual order
- Run `npx lighthouse --accessibility` — score ≥ 90
Verification steps should be:
- Executable: Commands or specific actions
- Deterministic: Same result every time
- Mapped to criteria: Clear which criterion each step validates
For accessibility legs, include specific checks:
- Keyboard navigation sequences to test
- Screen reader commands (e.g., "navigate to main content via skip link")
- Automated tool commands (Lighthouse, axe-core)
Implementation Guidance
Provide specific direction when needed:
## Implementation Guidance
Use Prisma's native type for id:
```prisma
id String @id @default(cuid())
For timestamps, use Prisma's auto-managed fields:
created_at DateTime @default(now())
updated_at DateTime @updatedAt
Do not add relations to Post/Comment yet—that's a separate leg.
Implementation guidance helps when:
- Project has specific patterns to follow
- There are multiple valid approaches (pick one)
- Constraints aren't obvious from context
### Files Likely Affected
Help the AI know where to look:
```markdown
## Files Likely Affected
- `prisma/schema.prisma` - Add User model
- `prisma/migrations/*` - New migration file (generated)
This isn't prescriptive—the AI might touch other files. It's a starting point for orientation.
Leg Lifecycle
Legs progress through defined states:
States
planning ──► ready ──► in-flight ──► landed ──► completed
│
└──► aborted
planning Leg is being designed. Acceptance criteria and implementation guidance being defined.
ready Leg design approved. Ready for implementation.
in-flight AI agent actively working on implementation.
landed Implementation complete. Flight log updated. Ready for review.
completed Review passed. Acceptance criteria confirmed met.
aborted Leg cancelled. Changes are rolled back. Document the reason in the flight log.
State Transitions
| From | To | Trigger |
|---|---|---|
| planning | ready | Design review passes |
| ready | in-flight | Developer begins work |
| in-flight | landed | Developer reports completion |
| in-flight | aborted | Cannot proceed, changes rolled back |
| landed | completed | Review passes |
| landed | in-flight | Issues found, needs fixes |
Note: Legs may only be modified while in planning state. Once in-flight, create new legs instead of modifying existing ones.
Patterns for AI Consumption
Be Explicit, Not Implicit
Implicit (requires inference):
Add validation to the email field
Explicit (no inference needed):
Add email validation: must be non-empty, valid email format (use validator library's isEmail), maximum 255 characters. Return 400 status with
{ error: "Invalid email format" }on failure.
Provide Examples
When patterns might be unclear, show don't tell:
## Implementation Guidance
Follow the existing controller pattern:
```typescript
// Example from PostController
export async function createPost(req: Request, res: Response) {
const { title, content } = req.body;
if (!title) {
return res.status(400).json({ error: "Title is required" });
}
const post = await prisma.post.create({
data: { title, content, authorId: req.user.id }
});
return res.status(201).json(post);
}
Apply this pattern to the registration endpoint.
### State Constraints Clearly
Don't bury constraints in prose:
**Buried**:
> Create the endpoint and make sure it handles errors properly and validates input and also we're using Express and the response should be JSON.
**Clear**:
```markdown
## Constraints
- Framework: Express.js
- Response format: JSON
- Error handling: Return appropriate HTTP status codes
- Validation: Validate all input before processing
Link to Flight for Context
When details would be redundant, reference the parent:
## Context
See [parent flight](../flight.md) for:
- Authentication approach (JWT tokens)
- Session duration decisions
- Error response format standards
Common Pitfalls
Too Large
If a leg takes more than a few hours, it's probably too big. Signs:
- Multiple independent pieces of functionality
- Would benefit from intermediate checkpoints
- Hard to write clear acceptance criteria
Split into smaller legs.
Too Small
If a leg is trivial, it adds overhead without value. Signs:
- Single line change
- No meaningful acceptance criteria
- Part of a larger atomic operation
Combine with related work.
Ambiguous Acceptance Criteria
If criteria require judgment, they're not criteria:
Ambiguous: "Code is clean and readable" Specific: "Functions are under 50 lines, no eslint warnings"
Ambiguous: "Error handling is good" Specific: "All async operations wrapped in try/catch, errors logged with context"
Missing Context
AI agents don't have your mental model. Include:
- Why this approach (from flight decisions)
- How this fits with existing code
- What patterns to follow
- What to avoid
Relationship to Flight
Legs are generated from flights. The flight provides:
- Technical approach
- Design decisions
- Overall context
Legs provide:
- Specific implementation steps
- Explicit acceptance criteria
- Focused scope
A flight might generate many legs:
Flight: User Registration Flow
├── Leg: create-user-model
├── Leg: registration-endpoint
├── Leg: email-validation
├── Leg: password-hashing
├── Leg: registration-tests
└── Leg: registration-docs
Immutability Principle
Once a leg is in-flight, don't modify it. If requirements change:
- Mark the current leg as aborted (changes rolled back)
- Create a new leg with updated requirements
- Reference the old leg for context
This preserves history and prevents confusion about what the AI was asked to do.