Skip to Content

Generate HTML Reports

The ajat report commands turn an export snapshot into a single self-contained HTML file you can open offline, attach to a ticket, or archive for compliance. There are five reports, each a different lens on the automation estate. Pick the one that answers the question you have.

Every report reads the local JSON catalog on disk — no live Jira call is made. That means you can generate, review, and share reports without credentials and without touching the tenant.

ajat works with Atlassian Jira Cloud Automation only. It does not support Jira Server or Jira Data Center. Reports are generated from a local export produced by ajat export against a Jira Cloud tenant.

The five reports

ReportAnswersAccent
inventoryWhat automation do we have, who owns it, and where does it send data?blue
collisionWhich rules overlap or are copy-paste duplicates?orange
consistencyIs the estate labelled, named, and owned consistently?violet
riskWhat is broken, unowned, wasteful, or risky?red
workflowWhat does each rule actually do, step by step?teal

Each report ships with its own accent palette so it is recognisable at a glance. All five share the same navigation chrome — client-side search, foldable sections, sortable tables, light/dark themes, a Print button, and links into Jira when the snapshot captured the site: every rule opens on its own page, and projects, people, and JQL searches open on theirs (see Links into Jira).

The reports exist for the problem that appears once Jira Automation grows across an organization: no single project screen explains the whole automation mesh. An export snapshot may contain local project rules, multi-project rules, global rules, copied rules with small differences, labels that mean different things in different teams, and webhook or email actions that connect Jira to other systems. The reports turn that local JSON estate into an inventory and review surface that administrators, auditors, and migration teams can discuss without live Jira access.


Inventory

What it does: catalogues every rule in the export snapshot, grouped by scope. It is the baseline map of the automation estate — what exists, where it lives, whether it is enabled, and which triggers, conditions, actions, labels, actors, and branches make up each rule.

ajat report inventory \ --input-dir ./jira-automations-backup \ --output-file inventory.html

What you get:

  • Headline hero card plus metric cards: total / enabled / disabled / unique scopes / branching / chain-capable / unlabeled.
  • Scope-family breakdown with inline bar charts (global, single-project, multi-project, other-scope, unknown).
  • Recently edited and Oldest rules tables — the first surfaces current activity, the second surfaces potentially stale rules nobody has touched in a long time.
  • Unlabeled rules list (rendered only when any are missing labels).
  • Top scopes / triggers / actions with bars proportional to count; trigger and action types are humanised (e.g. jira.jql.scheduled → Scheduled (JQL)).
  • Top labels chips and Top actors table.
  • People section — a per-account table covering everyone the estate references (owners, actors, collaborators, and component references), with per-role rule counts, total rules, account type, and active/deactivated status.
  • One expandable card per rule with status badges, a Trigger → Conditions → Actions → Branches flow diagram (with inline hints such as the cron expression for scheduled triggers, JQL excerpts, and target field names), a copy-to-clipboard button for the UUID, and a metadata grid (UUID, state, labels, updated, created, actor, notify-on-error, source file).

Integration footprint

The inventory report answers a security and compliance question the Jira UI cannot: where does our automation send data, and to whom? The integration footprint inventories every external service the estate reaches — chat spaces, email recipients, webhook endpoints, and cloud services. Use it during vendor reviews, data-egress audits, and access reviews to see the automation’s outbound dependencies in one place.

The inventory report is the right first stop when a team asks, “What automation do we actually have?” It shows the global and cross-project rules that are easy to miss when each project is reviewed in isolation.


Collision

What it does: finds rules that overlap or do the same thing — the copy-paste sprawl that accumulates as automation is cloned across projects.

Why it’s useful: duplicated rules are extra maintenance, extra runtime, and extra places for the same logic to drift out of sync. This report gives you a shortlist of consolidation candidates and conflicting rules that fight over the same issues.

ajat report collision \ --input-dir ./jira-automations-backup \ --output-file collision.html \ --similarity 0.7

Two kinds of duplication are detected:

  • Behavioural duplicates — rules whose steps are near-identical (trigger, conditions, and actions with their key parameters), clustered by Jaccard similarity regardless of scope, so the same automation copy-pasted into many projects surfaces as one family. Each cluster shows the shared behaviour, each member’s similarity, and what it differs by. Tune with --similarity.

  • Overlap fingerprints — coarser structural matches:

    GroupConfidenceWhat it surfaces
    Exact fingerprintHIGHSame scope + trigger + condition bundle
    Shared triggerMEDIUMSame trigger in the same scope
    Shared conditionLOWRepeated condition fragment under the same trigger
    Shared labelLOWRules tagged with the same automation label

Confidence reflects how specific the match is. Always inspect the listed rules before consolidating — duplicates are sometimes intentional (e.g. one rule per project clone). The report surfaces candidates for human review; it never claims a rule is wrong.


Consistency

What it does: audits label hygiene, naming, ownership, and governance posture across the estate.

Why it’s useful: it is the readability lens. As more projects and admins participate, labels and names drift and ownership gets murky. This report shows whether teams use the same language for the same kinds of automation — valuable before migrations, platform cleanup, and access reviews.

ajat report consistency \ --input-dir ./jira-automations-backup \ --output-file consistency.html

What you get:

  • Label inventory: every label with its rule count and the projects its rules belong to, each project listed once, plus a Global or Other tag when global or other-scope rules carry it. Sort by the Projects column to find the labels used most widely.
  • Similar labels: clusters detected via normalized Levenshtein distance (threshold 0.82) — catches typos like triage vs triag.
  • Similar rule names: the same algorithm on rule names — surfaces copy-pasted rules with slightly different names.
  • Capability families: rules grouped by inferred action family (issue creators, issue modifiers, email senders, webhook callers).
  • Governance & hygiene: error-handling and edit-access distributions, plus drill-downs of silent-failure and restricted-access rules.
  • Ownership: who authors and runs the automation, and the “orphaned” rules whose author or run-as identity is deactivated.

Risk

What it does: scans the estate for governance and operational risk, scores each rule, and ranks the ones that need attention — a health dashboard with an overall grade.

Why it’s useful: scale hides problems. This report finds the automation that is quietly failing, unowned, stale, wasteful, or leaking data — the issues you cannot see rule-by-rule in Jira. Run it quarterly, or diff it over time.

ajat report risk \ --input-dir ./jira-automations-backup \ --output-file risk.html

Every rule is checked against the findings below. Each finding is worth a fixed number of points, a rule’s score is the sum of the findings it trips, and the report lists the exact reasons beside every rule — one chip per finding, coloured by severity.

FindingSeverityPointsCountsWhat it flags
Throttled runshigh30all rulesJira stopped at least one run for breaching a service limit. Needs execution history from ajat audit-log. Disabled rules are listed too: repeated throttling is how Jira disables a rule.
Exposed secretshigh30all rulesA token, key, or password written into the rule: Google Chat or Slack webhook URLs, key= or token= in a URL, a literal Authorization or webhook-token header, GitHub, AWS, Atlassian, Slack, or Google token shapes. Smart values such as {{secrets.x}} are not flagged.
Silent failureshigh30all rulesnotifyOnError = NEVER; when they break, nobody is told.
Runs as a deactivated accounthigh30all rulesThe run-as identity is deactivated or unresolved.
Deactivated user referenceshigh30all rulesAn action references an account that no longer exists.
Sub-hourly scheduleshigh30enabledA schedule fires more than once an hour, work or not.
Broad trigger across projectshigh30enabledA broad trigger (below) in global or multi-project scope: its volume grows with the site.
Unbounded searcheshigh30enabledA scheduled search (without “only changed work items”) or a JQL branch matches more than 1000 work items, or has no time window, so every match reruns the steps after it. These are the rules that hit Jira’s search limit and get throttled. With ajat export --probe-jql the real count decides; with execution history, a run that touched 100 or more work items is flagged too.
Unowned (author deactivated)medium15all rulesThe author has left; nobody owns the rule.
Stale but enabledmedium15enabledUntouched for over a year, yet still live.
Runs without actionsmedium15enabledRan at least 10 times without performing an action, or its last run that did anything was 15 or more days before its latest. Needs execution history from ajat audit-log.
Broad triggersmedium15enabledWork item updated, comment added, or field value changed on any field, in one project.
Hourly schedulesmedium12enabledA schedule fires every hour, work or not.
Searches and web requests on every runmedium10enabledLookups and outgoing web requests add steps to each execution.
High complexitymedium10all rules15 or more components.
External data egresslow5all rulesThe rule reaches a third-party service.

Cost findings count enabled rules only, because a disabled rule fires nothing. Jira bills automation in steps — each trigger, condition, action, and branch iteration that runs — so these are the rules that drive usage up. Governance findings apply to disabled rules too, since they are about what the rule would do and who can fix it. The points legend in the report is generated from the same table the score uses, and each cost finding is badged enabled rules.

A search counts as having a time window when it compares a date field with >, >=, or = against a relative date, now(), or a start-of function (updated >= -1d, duedate = startOfDay()), is anchored on specific work items (key = {{issue.key}}, parent = ABC-1), or is a text search. updated <= -7d is not a window: it selects everything older than a week, which grows without limit.

That reading of the JQL text is a fallback. Export with --probe-jql and the report uses Jira’s own count instead: a search over 1000 work items is flagged with its size (“scheduled search matches 3,588 work items”), and a counted search under 1000 is not flagged at all. On a real 654-rule estate the text alone flagged nine searches; the probe cleared eight and confirmed one. See Probing search sizes.

With execution history from ajat audit-log — Jira’s audit-log CSV export, imported, or the log itself, fetched (experimental) — a Busiest rules table ranks the 20 rules with the most runs, beside how many of them did nothing, throttling, the most work items one run touched, and the risk score, so cost and risk can be read together.

The overview grades the estate A–F from the points across all rules and lists the top at-risk rules, each with one chip per finding in its Why column; a Risk by project table routes findings to the owning team and links each project to Jira. Every finding’s list says, under each rule, why the rule is in it, with the same severity-coloured chips (“Secret: Google Chat webhook key and token in the URL”, “Throttled 7 times in the audit window”). Search matches findings and reasons too: typing secret or throttled finds the rules, not only the section. Add --state enabled to score only the rules that run (see Common flags).

Secrets are never printed. A secret finding names what kind of secret it is and where it sits in the rule (“Google Chat webhook key and token in the URL (Webhook › url)”), never any part of the value. Every report also masks credentials in the configuration text it quotes; see Sharing reports securely.

Identity-based findings (orphaned ownership, deactivated references) require an export made with --resolve-users, which ajat export writes by default. Without resolved identities the report falls back to raw account IDs and skips the ownership findings.

Risk grades drop on most estates after upgrading to v1.0.8. Seven findings are new, four of them high severity. On a real 654-rule export the grade went from C (60) to F (21), with exposed secrets alone accounting for about 27 points. The rules did not change; the report now sees more. Work through Exposed secrets first: rotating those and moving them into Jira’s secret store recovers most of the grade.


Workflow

What it does: renders every rule as a top-down flow diagram plus a step-by-step “runbook” of exactly what it does — print-friendly, one rule per page.

Why it’s useful: it is the fastest way to understand an automation without reading raw JSON or clicking through the Jira builder. Perfect for reviews, audits, change approvals, and onboarding someone new to the estate. Print or Save-as-PDF for a clean per-rule document.

ajat report workflow \ --input-dir ./jira-automations-backup \ --output-file workflow.html

Each rule shows its component tree as an inline-SVG flowchart (trigger → conditions → actions, with branches indented) alongside a plain-language step list (“When scheduled every 5 minutes → For related issues → Then edit Expected Release”), the owner and run-as identities, complexity, and the external systems it integrates with. Diagrams are inline SVG with no JavaScript, so the browser’s Print / Save-as-PDF produces a clean per-rule runbook.


Every report shares the same chrome:

  • One visual language. A rule, a person, a project, and a state look the same in every report: a disabled rule carries a Disabled badge in every list; a person is their picture and name, linked to their Jira profile, with a dot only when the account is inactive or unresolved; a project is a coloured key chip with the project’s icon that links to Jira; every rule’s Open in Jira goes to that rule’s own page; and severity (risk) and confidence (collision) share one palette, high to low. Large numbers use thousands separators everywhere, charts included. A rule’s schedule is classified once, so the charts, the inventory’s Hourly or faster flag, and the risk findings always agree.
  • Global search. The sidebar input filters every searchable element on the page — rule cards, recently-edited rows, label rows, cluster headings, risk findings and their reasons. Type several words in any order: each word has to appear somewhere in the entry, so kpi edit finds Edit and Check — Monitor and Modify KPI Value. Every word is highlighted inline. Sections that ship collapsed open while they hold a match and close again when the search clears.
  • Result counter. Under the search box, for example 37 of 648 rules. It counts the things the report is about — rules in the inventory and workflow reports, groups in collision and consistency, findings in the risk report.
  • No results. When nothing matches, the report says so and offers one button that clears the search and every chip.
  • Long lists. Lists that can run long — unlabeled rules, each risk category — are complete in the file and clipped after about 25 rows behind a Show all button. A search that matches below the fold opens the list for you, so the counts and the search always agree with what you can reach.
  • Filter chips (inventory and workflow): grouped into State, Scope, and Traits. A rule must match one chip from each group you use, and any one chip within a group, so Disabled + Scheduled shows rules that are both, while two scopes show either. The panel spells the active combination out in words. Chips narrow the rule catalog only; the summary tables and the People section follow the text query alone. Chips are buttons: reachable with Tab, toggled with Space or Enter.
  • Sort dropdown (inventory only): name A→Z / Z→A, updated newest / oldest, for the rule cards.
  • Sortable tables. Click any table header to sort by that column; click again to reverse it. Numbers sort largest first, text A→Z, and the header shows ▲ or ▼. Columns sort by their real value, not by what is printed: a ”·” counts as zero, “3 d ago” sorts by date, a bar by its number, a person by name, a severity from high to low. Free-text columns (the risk report’s Why) do not sort. Sorting keeps the current search, headers work from the keyboard, and screen readers announce every table by name and every header with its sort order.
  • Narrow screens. Wide tables scroll sideways inside their section instead of widening the page.
  • Foldable sections. Every titled section collapses; expand or collapse all from the sidebar buttons or the e / c keyboard shortcuts.
  • Analytics panel. The estate charts are the same in every report. They open by default in the inventory and start collapsed in the others, so each report’s own content comes first. The How often scheduled rules run chart groups scheduled rules by the time between two runs: under an hour, 1–23 hours, 1–6 days, 1–4 weeks, and monthly or less. The inventory’s Hourly or faster card, chip, and badge count the rules that run an hour or less apart.
  • Light / dark theme toggle in the top-right toolbar; the choice is persisted in localStorage. Without an override the report honours the OS preference, with no flash of the wrong theme.
  • Keyboard shortcuts: / focuses the search, Esc clears it from anywhere on the page, e expands every fold, c collapses every fold. Each one acts only when pressed on its own, so your browser’s Copy, Find, and Save keep working. The browser’s own Find (⌘F / Ctrl+F) is the right tool for text the sidebar index does not cover, such as rule descriptions and step details.
  • Print stylesheet. The toolbar, sidebar, search, chips, and copy buttons are hidden; sections render in a paginated layout suitable for PDF export (⌘P / Ctrl+P). Printing opens every collapsed section and folded list first, so the whole report prints, and closes them again afterwards. Pictures print with the page.
  • Email addresses are links. The notification-targets table and the per-rule recipient badges are mailto: links, with a copy button beside each address in the table.

Reports use modern HTML (<details>, CSS Grid, custom properties) and target evergreen browsers — current Chrome, Safari, Firefox, and Edge.

Common flags

Every report subcommand accepts:

FlagDefaultNotes
--input-dirrequiredDirectory produced by ajat export — must be provided explicitly. No Jira API calls are made; reports read disk only.
--output-file(per-report)Path of the HTML file to write (inventory.html, collision.html, consistency.html, risk.html, workflow.html).
--title(per-report)Override the report title.
--theme-filenoneYAML theme file: colour overrides and service names for white-label output (see Theming).
--remote-avatarsfalsePoint at Jira’s hosted avatar images instead of the pictures embedded from the export (see Pictures and offline use).
--stateallall, enabled, or disabled (any case). Keeps only rules in that state; every count, chart, and score describes the subset, and the header says Enabled rules only or Disabled rules only.
--workers8Concurrent local JSON loaders.

collision additionally accepts --similarity (default 0.7) to tune the behavioural-clustering threshold from 0 to 1.

# Risk over the rules that actually run. ajat report risk --input-dir ./jira-automations-backup --output-file risk-live.html --state enabled # Inventory of disabled rules, for a clean-up review. ajat report inventory --input-dir ./jira-automations-backup --output-file disabled.html --state disabled

Pictures and offline use

People appear with their Jira picture and a link to their profile, and projects with their icon. The pictures come from the export: ajat export downloads each resolved account’s 48×48 avatar into .ajat_external_directory.json and each project’s icon into .ajat_projects.json (see Resolving user identities), and a report embeds each one once, so a page with the same person on four hundred rules carries one copy of their picture, about 4 KB. The report stays a single file that opens offline, can be attached to a ticket, and fetches nothing from Atlassian when it is opened.

An account without a picture — the export ran with --avatars=false, the download failed, or the account could not be resolved — shows coloured initials instead. Exports made before pictures existed show initials for everyone until the next ajat export.

Pass --remote-avatars to point at Jira’s hosted images instead of embedding them. The page is smaller, but it only shows faces online, and every open tells Atlassian — including when someone you shared the estate with opens it. On a 654-rule export that is roughly 1400 image requests per open. Project icons stay embedded either way: Jira has no public address for them, and an estate has a handful at a kilobyte each.

ajat report inventory \ --input-dir ./jira-automations-backup \ --output-file inventory.html \ --remote-avatars

Every rule’s Open in Jira opens that rule’s own page. Jira keeps a single-project rule under the project’s settings, at a path that depends on the project’s type and style (/jira/software/c/projects/KEY for a company-managed software project, /jira/software/projects/KEY for a team-managed one, /jira/core/... for business and /jira/servicedesk/... for service management), which the export records in .ajat_projects.json. Global, multi-project, and other-scope rules — and every rule of an export made before that file existed — open under the global automation page, which lists them all.

The header’s Jira link still goes to the global automation page; a project chip opens the project, including in the risk report’s Risk by project table; a person opens their profile; and a JQL search shown on an inventory rule card runs that search in Jira. A search the page masks a secret out of is never linked.

Theming for white-label use

Reports use CSS custom properties for every color and radius. Override them with a YAML theme file to match your organization’s brand:

# brand-theme.yaml colors: bg: "#0d1117" surface: "#161b22" ink: "#e6edf3" accent: "#7c3aed" trigger: "#f59e0b" condition: "#a855f7" action: "#22c55e" branch: "#06b6d4"
ajat report inventory \ --input-dir ./jira-automations-backup \ --output-file inventory.html \ --theme-file ./brand-theme.yaml \ --title "Acme — Jira Automation Inventory"

Both halves of every override are validated against an allowlist: the key must be a plain CSS identifier, and the value a hex colour, a named colour or keyword, a numeric length or percentage, or an rgb() / rgba() / hsl() / hsla() call. Anything else is dropped — including url(...), which would make an otherwise self-contained report fetch a remote resource. Colour overrides cannot change a report beyond its colours.

Naming your own services

Reports name well-known services (“Slack”, “Microsoft Teams”) wherever a rule calls out to them: the inventory’s integrations, the risk report’s external calls, and the workflow pages. Any other host is shown by its domain. The same theme file can name your own and your vendors’ hosts:

# brand-theme.yaml services: factorialhr.com: Factorial HR api.acme.internal: Acme API

A key matches the host itself and every subdomain of it, and the longest matching key wins, so eu.api.acme.internal above is “Acme API”. A key must be a lowercase host name with at least one dot, and a label 1–40 characters with no <, >, ", or line breaks; entries that fail either check are dropped. Your names are used before the built-in ones, so a theme can also rename a service the reports already know.

Sharing reports securely

Reports quote parts of your rule configuration: webhook hosts, email recipients and subjects, comment text, JQL, and rule descriptions. They do not print full webhook URLs or header values, and every quoted piece of configuration is masked: token shapes and the values of key=, token=, and similar URL parameters are replaced with ••••••. The risk report’s Exposed secrets finding lists the rules that carry a credential, so you can rotate it and move it into a secret store.

Do not rely on ajat export --redact-sensitive-fields for this. On a real export it changed nothing for webhook URLs that carried a key and a token. The exported JSON on disk still contains every secret, so protect the export directory itself. Treat exports and reports as confidential and share them accordingly.

Masking catches known shapes, not every possible secret. Scan a report before mailing it externally:

grep -i 'password\|token\|secret\|apikey' inventory.html

A report enriched with resolved identities contains personal data: display names, pictures, and any email addresses Jira exposed. Handle it as you would any file containing personal data.

  • ajat export — build the local export snapshot that reports consume.
  • ajat audit-log — bring rule execution history into the export, so the risk report sees throttled runs, runs without actions, and the busiest rules.
  • ajat diff — compare two export snapshots to review drift over time.
  • ajat search — query the live tenant for fresh rule summaries without exporting.
  • Utilities — doctor, tree, support, and the rest of the diagnostic surface.
Last updated on