Rules cookbook: common setups
Copy-ready recipes for EngLedger's four rule engines: classify projects, route commits, auto-fill initiatives and put sensible AI spend controls in place.
Updated 12 July 2026
EngLedger has four rule engines. Each one automates a different decision, and they don't overlap. A rule in one engine never changes what another engine decides.
| Engine | What it decides | Where it lives | Evaluation model |
|---|---|---|---|
| Ticket rules | A ticket's financial classification, work type and categories | Classification → Ticket Rules | Priority order, first match wins, fallback if nothing matches |
| Commit rules | Classification of commits with no usable ticket link | Classification → Commit Rules | First match wins; a linked ticket or manual override takes precedence |
| Initiative rules | Which tickets belong to an initiative | Each initiative's Rules page | Additive: every active rule links every ticket it matches |
| AI spend rules | What happens when metered AI spend hits a cap | AI Spend Control | All caps covering a person apply together; exempt short-circuits |
This page is a set of recipes: which engine, the exact conditions, and how to check the rule did what you meant. The deep guides ( the classification rules reference, teams and initiatives and AI spend controls) explain each engine's full behaviour; the recipes just point at them where it matters.
Classifying tickets
Ticket rules live under Classification → Ticket Rules. Conditions on a rule are ANDed, matching is case-insensitive, and the first matching rule by priority wins. The rules reference covers every field and operator.
Capitalise a project's work
For a project that is clearly R&D (a new product build, a replatform) classify the whole project rather than ticket by ticket.
Add a rule with one condition: Issue key · starts with ·
PROJ-(your project's key prefix). If capitalisable work is instead tagged across projects, use Labels · includes ·capex.Set the output: financial classification Capitalisable, work type Feature.
Check the rule builder's test count and sample issue keys before saving. The count respects priority, so it shows what this rule would actually capture.
New rules only apply to newly synced tickets. To sweep existing work, run Reclassify all tickets from the rules page.
Classify by component or issue type
The workhorse setup: map your tracker's own structure onto work types.
Bugs as maintenance: Issue type · equals ·
Bug→ work type Maintenance, non-capitalisable.A component as support: Components · includes ·
customer-support→ work type Support.Several types with one rule: Issue type · is one of ·
Bug, Incident, Hotfix(comma-separated, spaces ignored).Order matters: put narrower rules (a specific component) above broader ones (all bugs), because the first match wins.
Verify in the ticket review screen: freshly synced tickets of that type should show the rule as their classification source, and the rule's match count on the rules page should climb.
Keep an ops ticket type out of the ledger
Some work shouldn't be classified at all: service desk tickets, HR tasks in a shared Jira. This isn't a rule; it's the Excluded ticket types list on the same Ticket Rules page.
On Classification → Ticket Rules, find the excluded ticket types section and toggle the type on (for example
Service Request).Excluded types skip the rule engine entirely and stay out of the ledger and reports. They are marked excluded, not classified.
Exclusion is stronger than a rule: an excluded type never reaches the rules, whatever their priority.
Classifying commits
Commit rules live under Classification → Commit Rules and only touch commits with no usable ticket link. Linked commits inherit the ticket's classification. Fields are branch name, commit message and file path.
Route docs-only and hotfix commits
Docs-only commits: File path · matches (regex) ·
/\.(md|mdx)$/→ non-capitalisable. The condition matches if any changed file matches, so add a message or branch condition if you want strictly-docs commits only.Hotfix and release branches: Branch name · matches (regex) ·
/^(hotfix|release)\//→ work type Maintenance.Test with the preview panel: paste a branch name or file list and see which rule would match before any real commit is touched. Regex that fails to compile never matches (it doesn't error) so always preview.
Any commit rule change re-runs classification automatically for rule- and fallback-classified commits, so there's no reclassify step here.
Filling initiatives
Initiative rules live on each initiative's Rules page and use the same condition fields as ticket rules. The semantics differ: membership is additive. Every active rule links every ticket it matches, and links are never removed automatically. Details in teams and initiatives.
Auto-assign an epic's tickets to an initiative
For epic-shaped work you don't need a rule at all:
On the initiative, use Add ticket and add the epic itself as an item.
An epic item counts as the epic and all its child tickets, current and future. Effort on any child rolls up without adding children one by one.
If the work is tagged rather than epic-shaped, use a rule instead:
Labels · includes · platform-migration. Rules re-evaluate after
every sync, so newly tagged tickets join on their own. Check the rule's
preview before saving. A too-broad rule quietly inflates the
initiative's cost.
Split shared work across initiatives
When a ticket or epic serves two initiatives, link it to both and use cost splits so its effort isn't counted twice.
- Add the ticket (or epic) as an item on both initiatives.
On each initiative's items list, set the item's cost split, say 60% on one and 40% on the other. Splits are manual; rule-created links always start at 100%.
The split applies to everything the item brings in: an epic at 40% contributes 40% of the effort on the epic and all its children, and 40% of the AI spend attributed to those tickets.
EngLedger warns when a ticket's splits don't sum to 100 across initiatives, but doesn't block. Rebalance from the warning on the item. Splitting across teams works differently: team cost isn't rule-driven at all, it follows dated team membership and team filters on reports.
Controlling AI spend
Spend rules live on the AI Spend Control screen. A rule's scope comes from its conditions (Team, Person, Model, Provider, Day of week, Time of day); its teeth come from the action: block, restrict models, rate limit, alert only or exempt. Unlike classification, all caps covering a person hold at once. Full behaviour in AI spend budgets, limits and enforcement.
Cap a team's monthly AI spend: alert-only first
Add a rule with condition Team · is · your team, a monthly limit in your currency (or a percentage of the organisation budget), and action Alert only.
Watch a full period. Alert-only notifies admins at 50%, 80% and 100% of the limit without anyone losing access, the right mode while the budget is still a guess.
Once the number settles, edit the rule's action to Block or Restrict models. Use the dry-run preview to see who a change would affect before it enforces anything.
Restrict expensive models outside working hours
A standing policy rather than a budget: no limit, conditions define when it applies.
Add a rule with condition Time of day · not between ·
09:00–17:00, no limit, action Restrict models, listing the high-cost models to deny (or switch the restriction mode to allow-only and list the cheap ones).Conditions on one rule are ANDed, so covering weekends too takes a second rule with a Day of week condition.
Verify on the status strip: outside the window the scope shows Restricted, and access-window restrictions clear at the window boundary rather than holding until a period reset.
Exempt a service account from spend rules
CI pipelines and automation accounts shouldn't trip budgets meant for people.
Add a rule with condition Person · is · the service account's person record, and action Exempt.
Exempt short-circuits everything: a matching person is excluded from every other spend rule, whatever its priority or scope.
Exemptions are visible in the rule list like any other rule. An exemption you can't see isn't governance. The same honest-numbers posture applies as everywhere else in AI governance.
Rate-limit a heavy experimenter instead of blocking
When one person's legitimate experimentation dominates a team budget, slowing is often better than stopping.
Add a rule with condition Person · is · the person, action Rate limit, and set the requests-per-minute and tokens-per-minute caps.
Where several rate limits apply to one person, the lowest caps win. Rate-limited people appear under the Restricted state in the live status, with the per-minute caps in force.
The person keeps access at a sustainable pace, and the notification they receive is short and neutral, a budget mechanism, not a judgement about how anyone works.
Split one budget into team shares
The common shape: a single organisation budget, carved into shares so no team can quietly eat everyone else's headroom.
Set the Organisation budget to the whole amount — say 2,000 a month. Every percentage below is a share of this number.
Add one rule per team with condition Team · is · that team, a % of org budget limit, and action Block: engineering 60, data 25, support 15.
Each share is measured against that team's combined spend, so a team of five sharing 20% breaches when the five of them together reach the share — not when one of them does.
Shares need not total 100. Leaving headroom unassigned is deliberate: the organisation budget still applies to everyone, so an unassigned remainder acts as slack rather than a share anyone owns.
Allow one model but not another from the same family
Family patterns like claude-* cover every model in the family, which is
the wrong tool when you want the cheap one and not the expensive one.
Add a rule with action Restrict models and mode Allow only, then pick the specific models by name rather than a family.
Check the picker is showing the model names your tools actually send. Rules match the exact name on the request, so a dated variant is a different model from its undated alias.
If a model you expect is missing from the picker, use Resync models. The freshness of the list is shown next to that button.
Catch a one-day spike a monthly budget would miss
A monthly cap says nothing about how fast it is spent. A runaway script can burn a fortnight of budget in an afternoon and still sit inside the month.
Keep the monthly budget as the ceiling.
Add a second rule, same scope, with a Daily period and a limit around a normal day's spend, action Block or Alert only.
Both caps apply at once, so the daily guard stops the spike while the monthly budget keeps governing the total. Daily windows are measured against live usage rather than the overnight rollup, so a spike shows up the same day.
When a recipe doesn't take
- A ticket rule didn't fire. Check priority: an earlier rule may capture the ticket first. The rule builder's test count shows what a rule would catch from where it sits.
- Existing tickets unchanged after adding a rule. Creating a rule never reclassifies by itself; run Reclassify all tickets.
- A commit stayed put. Commits inherit from linked tickets and manual classifications are never overwritten; rules only see the rest.
- An initiative rule stopped matching but tickets remain. By design. Rules only add links; removing one is manual.
- A spend rule didn't enforce. Enforcement runs on a short evaluation cycle (about five minutes), and an exempt rule covering the person wins over everything.
Rule coverage across the classification engines is measurable: the fallback-classified work in the Confidence Report's grey zone is the list of tickets and commits no rule matched, the working to-do list for this cookbook, and the honest-coverage posture the rest of the ledger is built on.