| name | implement-card |
| description | Implement a Magic: The Gathering card (or batch of similar cards) from a genset stub. Writes failing tests first (TDD), then implements the card, then verifies all tests pass. Use when the user wants to implement a specific card or group of cards. |
| allowed-tools | Read, Edit, Write, Bash, Grep, Glob, Agent, AskUserQuestion, Skill |
| argument-hint | <card name(s)> |
Card Implementation Skill
You are implementing Magic: The Gathering cards for the mage-go engine. Follow TDD strictly.
Scope Boundary
You MUST only edit files in cards/. Do NOT edit files in pkg/mage/, pkg/mage/core/, or any other engine directory. If you need an engine change, return a structured engine feature request (see Step 5) so the orchestrator or user can route it to /implement-engine.
Arguments
Card name(s) to implement: $ARGUMENTS
Step 0: Load Context
Read the engine API reference and rules index:
Read pkg/mage/doc.go
Read docs/comprehensive-rules-index.md
The full MTG comprehensive rules are at docs/comprehensive-rules.md (~9200 lines). Do not read the whole file. Use the index to find the relevant section line number, then read just that section with Read offset=LINE limit=N. Consult the comp rules whenever:
- Oracle text uses a keyword or mechanic you need to understand precisely
- A card's interaction with game rules is unclear
- You need to verify timing, targeting, or replacement effect behavior
Step 1: Find the Card Stub
Search for the card(s) in the cards/ directory. The stub was generated by genset and contains:
- Full Oracle text as a comment
- A
// TODO: implement marker
- A basic skeleton (just the constructor, no abilities)
Grep for "$ARGUMENTS" or "TODO: implement" in cards/
Read the stub file to get the full Oracle text. The Oracle text is the single source of truth for what the card does. Read it carefully and plan the implementation.
Step 2: Consult Rules and XMage (if needed)
For complex mechanics or ambiguous Oracle text:
-
Comprehensive Rules first: Use the index (docs/comprehensive-rules-index.md) to find the relevant rule section, then read it from docs/comprehensive-rules.md with offset/limit. For example, if the card has banding, read the banding rules at line 3795+ (rule 702.21).
-
XMage second: Check XMage's implementation for how the card is wired:
Look in ~/mage/Mage.Sets/src/mage/cards/ for the card
Use an Agent with subagent_type=Explore to search XMage if the mechanic is non-trivial.
Step 3: Check for Similar Existing Implementations
Before writing code, search the codebase for cards with similar mechanics. This helps you:
- Reuse patterns (e.g., how other "when this creature dies" triggers work)
- Find the right Effect/Target/Filter constructors
- Match the project's coding style
Step 4: Write Failing Tests (RED)
Write tests BEFORE implementing the card. Test files go in the same package as the card (e.g., cards/legends/creatures_test.go).
What to test:
- Basic functionality: The card's primary effect works
- Positive cases: Effect triggers/resolves when conditions are met
- Negative cases: Effect does NOT trigger when conditions aren't met
- Vanilla creatures with only basic keywords (flying, first strike, etc.) and no special abilities do NOT need tests
- Each distinct ability or triggered/activated effect beyond basic stats and simple keywords SHOULD have at least one test
Test structure:
func TestCardName(t *testing.T) {
t.Run("descriptive_case_name", func(t *testing.T) {
g := gametest.NewTestGame(t)
})
}
Run the tests to confirm they fail:
go test ./cards/<set>/ -run TestCardName -v
The tests MUST fail at this point (card not yet implemented). Confirm RED status before proceeding.
Step 5: Implement the Card (GREEN)
Now implement the card to make the tests pass:
- Replace the stub in the appropriate file (creatures.go, spells.go, etc.)
- Keep the Oracle text comment above the Register call
- Remove the
// TODO: implement marker
- Use existing Effect constructors from doc.go whenever possible
- For custom behavior, use
FuncEffect or FuncContinuousEffect
- Implement EVERY condition, restriction, and detail from the Oracle text. Do NOT simplify. If Oracle says "nontoken," filter for nontoken. If Oracle says "you don't control," check controller. If Oracle says "with flying," filter for flying. A simplified implementation is a wrong implementation — this is a rules engine, not a shipped game. If something truly can't be implemented, mark it with
// XXX: and ask the user.
If new engine features are needed:
Do NOT edit pkg/mage/ yourself. Card agents must not modify engine code.
- First implement everything possible with existing features
- Run tests to see what passes and what still fails
- If a feature is missing from the engine, stop and return a structured engine request:
## Engine Feature Needed
### What's missing
[Describe the mechanic or capability the engine lacks]
### Cards blocked
[List the card(s) that need this feature]
### Oracle text driving the need
[Quote the exact Oracle text that requires this feature]
### Suggested approach
[Optional: how you think it could be implemented in pkg/mage/]
- The orchestrator (
/implement-set) or the user will route this to /implement-engine
- Once the engine feature is available, resume card implementation using the new API
If you are invoked standalone (not from /implement-set), use AskUserQuestion to tell the user what engine work is needed and ask them to run /implement-engine first.
Step 6: Verify All Tests Pass (GREEN)
Run the card's tests:
go test ./cards/<set>/ -run TestCardName -v
Then run ALL tests to ensure nothing is broken:
go test ./...
Both must pass. Fix any regressions.
Step 7: Handle Incomplete Implementations
There are two distinct cases:
Partially implementable (XXX marker)
If part of the Oracle text cannot be fully implemented yet but could be with future engine work:
- First, use AskUserQuestion to ask the user whether to skip the feature or attempt it
- If skipping: add an
// XXX: <explanation> comment explaining what's missing and why
- Never silently skip Oracle text behavior
Fundamentally unimplementable (UNIMPLEMENTABLE marker)
Some cards have mechanics the engine cannot support (subgames, wish/sideboard, etc.). These are permanently out of scope, not just waiting on engine work:
- Mark the card with a
// UNIMPLEMENTABLE: <reason> comment above or inside the Register call
- Register it as a no-op stub (e.g.,
NewSorcery("Shahrazad", "{W}{W}", nil) or NewArtifact("Ring of Ma'rûf", "{5}"))
- Add the card to
UNSUPPORTED.md in the set's directory. Create the file if it doesn't exist:
# [Set Name] — Unsupported Cards
Cards registered as no-op stubs because their mechanics cannot be implemented
in the current engine. Marked `UNIMPLEMENTABLE` in source.
| Card | Reason |
|------|--------|
| Card Name | Brief explanation of why it can't be implemented. |
XXX vs UNIMPLEMENTABLE: Use XXX when the gap is fixable with engine work. Use UNIMPLEMENTABLE when the mechanic is fundamentally beyond the engine's scope (recursive subgames, cards outside the game, etc.). Never use XXX for permanently impossible cards, and never use UNIMPLEMENTABLE for cards that just need engine features built.
Step 8: Commit
Use /commit to create a commit for the completed work. The commit should include:
- The card implementation(s)
- All new tests
- Any engine changes made to support the card(s)
Only commit files you changed in this session. Do not stage unrelated changes.
Important Rules
- Oracle text is law. Every behavior described in the Oracle text must be implemented, explicitly marked with
// XXX: (partial, fixable), or marked // UNIMPLEMENTABLE: (permanently out of scope). Cards marked UNIMPLEMENTABLE must also be listed in the set's UNSUPPORTED.md.
- NEVER simplify. Do not drop conditions, skip restrictions, approximate effects, or cut corners. Every word of Oracle text matters: "nontoken," "you don't control," "with flying," "can't be regenerated," "another" — all of it. A simplified implementation is a wrong implementation. This is a rules engine; correctness is the entire point. If you cannot fully implement something, mark it
// XXX: and ask the user. Never silently simplify.
- TDD is mandatory. Tests first, implementation second. No exceptions.
- No multiplayer. This engine is 2-player only. Skip multiplayer-specific effects (e.g., "each opponent" means just one opponent).
- Ask before cutting scope. If you think something can't be implemented, use AskUserQuestion. Don't decide on your own.
- Independent commits. Only commit your own work from this session.
- Consult doc.go. The engine API reference has 50+ effects, 20+ triggered ability constructors, targets, filters, costs, and complete examples. Use what exists before writing custom code.
- Consult comprehensive rules. When Oracle text involves keywords, timing, targeting, layers, replacement effects, or any mechanic whose exact behavior matters, look up the relevant rule in
docs/comprehensive-rules.md using the index at docs/comprehensive-rules-index.md. Read only the relevant section (use offset/limit).