Design Rules — Agent Workflow
How AI agents should capture design rules from debugging sessions, turning ephemeral pain into persistent, checkable project knowledge.
Why This Matters
Every FPGA debugging session produces hard-won knowledge: a property value that silently breaks DMA, a tool version that changes IP behavior, an interface configuration that "looks right" but fails at synthesis.
Without a capture workflow, this knowledge dies when the chat session ends.
Design rules are how it survives — they're automatically checked on every
rr rules check run, catching the same class of bug before it costs
another multi-day investigation.
This document defines the agent-side workflow for filing rules. For the
rules engine internals, see the built-in rules at
sdk/engine/builtin_rules.yml and the engine at sdk/engine/ip_rules.py.
When to File a Rule
File a rule when all three conditions are met:
- You found a real bug — not a hypothetical, not a best practice
- The root cause is a checkable property — a QSYS parameter, an IP manifest field, a toolchain version, a component configuration value
- The bug class could recur — it's not a one-off typo or config mistake
Good candidates
| Scenario | Example |
|---|---|
| IP property causes silent failure | maximumPendingReadTransactions=0 hangs Avalon-MM |
| Tool version breaks existing config | Quartus 24.1 changes EMIF parameter defaults |
| Interface config looks valid but isn't | readLatency=0 without readdatavalid signal |
| Vendor edition mismatch | Standard vs Pro Quartus silently downgrades IP |
| Init sequence dependency | SGMII requires PHY→PCS→reset ordering |
Don't file a rule when
- The fix was a typo or one-off configuration mistake
- The issue can't be reduced to a checkable property + condition
- An existing rule already covers it (
rr rules listto check) - The issue is tool-environment-specific (PATH, permissions, OS quirks)
How to File (Non-Interactive)
AI agents must use the non-interactive CLI form since --from-incident
uses interactive prompts that agents can't respond to.
rr rules add \
--id CUSTOM-NNN \
--severity warning \
--message "What this rule checks for" \
--property "the_property_name" \
--condition "== bad_value" \
--incident "What happened, how long it took to find, what was misleading" \
--fix "Exact steps to fix it"
Required fields
| Flag | Purpose | Notes |
|---|---|---|
--id | Rule identifier | Use CUSTOM-NNN for project-local rules |
--message | What the rule checks for | Human-readable, one line |
--incident | The full bug story | Most important field — see below |
Optional but recommended
| Flag | Purpose | Notes |
|---|---|---|
--property | Property name to inspect | Makes the rule auto-checkable |
--condition | Comparison expression | == 0, missing, contains X, >= N |
--fix | Resolution steps | Exact commands, register offsets, settings |
--severity | error / warning / info | Default: warning |
Severity guidance
error— Will definitely break the build, synthesis, or hardware.rr rules checkreturns exit code 2.warning— Likely causes problems. Exit code 0 normally, 1 with--strict.info— Gotcha worth knowing. Logged but never fails.
Writing a Good Incident Story
The --incident field is what makes rules useful to future developers.
A rule without a story is noise — a rule with a story is a lesson.
Template
"Hit [symptom] on [board/project]. Root cause: [property] was [value] which causes [mechanism]. Took [time] to find because [what was misleading]. [Cost/impact if known]."
Examples from built-in rules
"Arria 10 TSE MAC project: DMA transfers would hang intermittently. Root cause: maximumPendingReadTransactions=0 (unlimited) with a fixed-latency master and variable-latency slave. The slave's waitrequest would back-pressure the interconnect, but with unlimited pending reads the master kept issuing reads until the fabric deadlocked. ~3 weeks debugging across RTL, SignalTap, and driver layers."
"MDIO reads to PHY returned PCS register values instead of PHY registers. Space 0 (PHY regs) is shadowed by the PCS register block when SGMII is enabled. Must access PHY via Space 1 (MDIO address offset 0x200)."
What makes a good story
- Specific: board name, IP version, tool version, property values
- Causal: explains why the value is dangerous, not just that it is
- Honest about cost: "took 3 weeks", "burned a tape-out slot"
- Notes what was misleading: "simulation passed", "no synthesis warnings"
Where Rules Are Stored
| Location | Purpose |
|---|---|
ip_rules.yml (project root) | Project-local rules — agents write here |
sdk/engine/builtin_rules.yml | Built-in rules shipped with RouteRTL |
Local rules with the same --id as a built-in rule override the built-in.
This lets projects customize severity or disable rules that don't apply.
Verification After Filing
After adding a rule, verify it loads correctly:
rr rules list # Should show the new rule
rr rules check # Should evaluate it against the project
If the rule has --property and --condition, rr rules check will
automatically scan QSYS/Platform Designer output and IP manifests for
violations.
Integration with CLAUDE.md
The rr init command generates a CLAUDE.md that includes agent directives
for rule filing. This is produced by sdk/engine/init/claude_md.py and
ensures every new RouteRTL project comes with the agent workflow built in.
The generated directives tell agents to:
- Run
rr rules checkbefore committing - Run
rr rules listbefore proposing IP configurations - File rules from debugging sessions using the non-interactive CLI
Condition Reference
Rules use simple condition expressions evaluated against property values:
| Condition | Matches when |
|---|---|
== 0 | Value equals 0 |
!= true | Value is not true |
missing | Value is null, None, or empty |
empty | Value is empty string, list, or dict |
>= 100 | Numeric value >= 100 |
<= 50 | Numeric value <= 50 |
contains xyz | Value contains substring "xyz" |
| (empty) | Always matches (informational rule) |
Related
rr rules check— Scan project against all active rulesrr rules check --strict— CI mode (warnings become errors)rr rules check --json— Machine-readable output for agent consumptionrr rules list— Display all rules with incident storiesrr rules add --from-incident— Interactive capture (humans only)- Built-in rules:
sdk/engine/builtin_rules.yml - Rules engine:
sdk/engine/ip_rules.py - CLAUDE.md generator:
sdk/engine/init/claude_md.py