---
title: "Lab: AI-assisted status reporting from Jira or Asana data"
description: "What you will build A weekly pipeline: pull work items from Jira (REST API) or Asana (CSV export) → compute a small set of metrics in code → draft the…"
url: https://optimizeall.com/learn/project-management-leadership-with-ai/ai-status-reporting-lab
updated: 2026-10-05
---

Project Management Leadership with AI · AI-enabled project management with governance · lesson 20 of 21 · 25 min

# Lab: AI-assisted status reporting from Jira or Asana data

## What you will build

A weekly pipeline: **pull** work items from Jira (REST API) or Asana (CSV export) → **compute** a small set of metrics in code → **draft** the narrative with an approved AI tool from the verified table only → **verify** every number and cause, add judgement, **publish** and record the AI use. Numbers always come from code, never from the model.

## Step 1a: pull issues from Jira Cloud

Jira Cloud's issue search uses `GET /rest/api/3/search/jql` with token-based pagination (`nextPageToken`, `isLast`); the older `/rest/api/3/search` endpoint was removed in 2025. Check Atlassian's current REST documentation if a call fails.

```python
import csv
import os
import requests

SITE = os.environ["JIRA_SITE"]            # e.g. https://your-company.atlassian.net
AUTH = (os.environ["JIRA_EMAIL"], os.environ["JIRA_API_TOKEN"])
JQL = 'project = CRM AND updated >= -90d ORDER BY created ASC'
FIELDS = "summary,status,assignee,duedate,created,resolutiondate,priority,labels"

rows, token = [], None
while True:
    params = {"jql": JQL, "fields": FIELDS, "maxResults": 100}
    if token:
        params["nextPageToken"] = token
    r = requests.get(f"{SITE}/rest/api/3/search/jql", params=params, auth=AUTH, timeout=30)
    r.raise_for_status()
    data = r.json()
    for it in data.get("issues", []):
        f = it["fields"]
        rows.append({
            "key": it["key"], "summary": f.get("summary"),
            "status_category": (f.get("status") or {}).get("statusCategory", {}).get("key"),
            "assignee": (f.get("assignee") or {}).get("displayName"),
            "due": f.get("duedate"), "created": f.get("created"),
            "resolved": f.get("resolutiondate"),
            "priority": (f.get("priority") or {}).get("name"),
            "labels": ";".join(f.get("labels") or []),
        })
    token = data.get("nextPageToken")
    if data.get("isLast", True) or not token:
        break

with open("work_items.csv", "w", newline="", encoding="utf-8") as fh:
    w = csv.DictWriter(fh, fieldnames=list(rows[0]) if rows else ["key"])
    w.writeheader()
    w.writerows(rows)
print(f"{len(rows)} issues written")
```

Create an API token in your Atlassian account settings and store it in an environment variable or a secrets manager. The `summary` field may contain personal or confidential text: it is used only locally and is **not** sent to the AI tool.

## Step 1b: or export from Asana

In Asana, open the project and use the export option to download CSV. Map its columns (for example Task ID, Name, Assignee, Due Date, Created At, Completed At, Section/Column) to the same names as above: `key, assignee, due, created, resolved, labels`.

## Step 2: compute defensible metrics

```python
import pandas as pd

df = pd.read_csv("work_items.csv", parse_dates=["created", "resolved", "due"])
for col in ("created", "resolved", "due"):
    df[col] = pd.to_datetime(df[col], utc=True, errors="coerce")
now = pd.Timestamp.now(tz="UTC")
done = df.dropna(subset=["resolved"])
weekly = done.set_index("resolved").resample("W")["key"].count().tail(6)
open_items = df[df["resolved"].isna()]
remaining = len(open_items)
fast, slow = max(weekly.max(), 1), max(weekly.min(), 1)
status = {
    "data_date": now.date().isoformat(),
    "completed_this_week": int(weekly.iloc[-1]) if len(weekly) else 0,
    "throughput_last_6_weeks": ", ".join(str(int(x)) for x in weekly),
    "open_items": remaining,
    "overdue": int((open_items["due"] < now).sum()),
    "no_owner": int(open_items["assignee"].isna().sum()),
    "no_due_date": int(open_items["due"].isna().sum()),
    "forecast_weeks_range": f"{-(-remaining // fast)} to {-(-remaining // slow)}",
    "top_risks": "; ".join(open_items[open_items["labels"].fillna("").str.contains("risk")]
                            .sort_values("priority").head(3)["key"]),
}
pd.Series(status).to_csv("status_table.csv", header=["value"])
print(pd.Series(status))
```

The status table holds only aggregates and issue keys, so it is safe to share with an approved AI tool under most policies (check yours).

## Step 3: the drafting prompt (any approved enterprise assistant)

```text
ROLE: You support the project manager of the CRM rollout. You draft; the PM verifies and decides.
DATA: The status table below is the ONLY source. Data date is in the table.
WRITE TWO VERSIONS:
A) Sponsor (≤ 120 words): headline; forecast range; the one decision needed; top risk.
B) Team (≤ 250 words): progress; overdue and ownerless items; forecast; risks; actions with owners if stated.
RULES: After every number, cite the column in [brackets]. Do not calculate new numbers or round them.
If a cause is not in the table, write "cause to be confirmed". British English. No dramatic adjectives.
TABLE:
<paste status_table.csv>
```

## Optional Step 3 via API (only if your organisation has approved API use)

```python
import os
import anthropic

client = anthropic.Anthropic()                     # reads ANTHROPIC_API_KEY from the environment
table = open("status_table.csv", encoding="utf-8").read()
prompt = open("status_prompt.txt", encoding="utf-8").read().replace("<paste status_table.csv>", table)
try:
    msg = client.messages.create(
        model=os.environ.get("ANTHROPIC_MODEL", "claude-opus-5"),   # check current model names in the docs
        max_tokens=2000,
        system="You draft project status reports from verified tables. Never invent numbers or causes.",
        messages=[{"role": "user", "content": prompt}],
    )
    if msg.stop_reason == "refusal":
        raise SystemExit("Request declined; review the input.")
    print("".join(b.text for b in msg.content if b.type == "text"))
except anthropic.RateLimitError:
    print("Rate limited: retry later.")
except anthropic.APIStatusError as e:
    print(f"API error {e.status_code}: {e.message}")
except anthropic.APIConnectionError:
    print("Network problem: check connectivity.")
```

Install with `pip install anthropic`. Other approved assistants (for example Microsoft 365 Copilot or ChatGPT Enterprise) can run the same prompt through their own interfaces.

## Step 4: verify, publish, record

```text
[ ] Every bracketed number matches status_table.csv (no rounding, no new numbers)
[ ] Every cause confirmed with its owner, or marked "to be confirmed"
[ ] The one decision needed is stated with who and by when (your judgement, not the model's)
[ ] Brackets removed; AI-assistance note added per policy
[ ] AI use register updated (tool, data, tier: medium, reviewer)
```

## How to measure success

- Time per weekly report (including review) versus the baseline.
- Corrections per report, by type (number, cause, tone), falling over time.
- Ownerless and undated items in the tool falling week by week.

## Video lecture: Lab: AI-assisted status reporting from Jira or Asana data

Lecture coming soon · 9 chapters · about 8 minutes. Read the full transcript below.

1. From tool data to a reviewed status report
2. Why this design
3. Step one: getting the data
4. Step two: metrics you can defend
5. Step three: drafting with an approved AI tool
6. Watch me do it: verify and publish
7. Worked example: a weekly cycle
8. Making it a habit, safely
9. Common mistakes, recap and try this now

## Lecture transcript

### From tool data to a reviewed status report

Every week, somewhere, a project manager copies numbers from Jira into a spreadsheet, pastes the spreadsheet into a slide, and writes three paragraphs explaining it, for the fourth time this month. It's necessary work. It's also exactly the kind of work that a small script and an approved AI assistant can do most of, leaving the project manager to do the part that matters: checking, interpreting and deciding. In this lab lecture I'll walk you through a practical pipeline. Pull work items from Jira's API or an Asana export. Compute a small set of metrics you can defend. Build a structured status table. Use a prompt template to draft the report. Then verify and publish. By the end, you'll have a workflow you can run every week in under half an hour.

### Why this design

Before we build it, here's the design principle, and it's the most important idea in this lab. Numbers come from code, not from the model. The script computes the metrics directly from the tool's data, so they're reproducible and auditable. The AI only drafts words, from a verified table, and it's told to cite the table for every number and not to invent causes. And a person verifies and owns the result. Why? Because language models are good at writing and bad at arithmetic under pressure, and they can transpose or invent figures that look entirely plausible. Separate the jobs, and you get the speed of AI with the reliability of code and the judgement of a person.

### Step one: getting the data

Step one: get the data. For Jira Cloud, the script calls the REST search endpoint with a JQL query, for example all issues in your project updated in the last ninety days, and pages through the results using the next-page token the API returns. It authenticates with your email and an API token, which it reads from environment variables. Never paste tokens into code or into an AI tool. The endpoint details changed in twenty twenty-five, so check Atlassian's current documentation if anything fails. For Asana, the simplest route is exporting the project as CSV from the project menu, which gives you task names, assignees, due dates, sections and completion dates. Either way, you end up with a table of work items with created, due and completed dates.

### Step two: metrics you can defend

Step two: compute metrics you can defend. Items completed this week, and the throughput trend over the last six weeks. Overdue items, meaning a due date in the past and not done. Items with no owner or no due date, which is a data quality signal in its own right. Remaining open scope, and a simple forecast range: remaining items divided by the fastest and slowest recent weekly throughput. If your team labels risks, issues and dependencies in the tool, pull the top items by priority. Keep it small. Six to eight numbers that answer: how much got done, is anything slipping, how clean is our data, and when are we likely to finish? The script writes these into a status table, which is the only thing the AI will see.

### Step three: drafting with an approved AI tool

Step three: drafting. Paste the prompt template from the lesson into your approved AI tool, followed by the status table. The template sets the role, supporting the project manager; the structure, a headline, progress, forecast, risks and decisions needed; and the rules. Cite the table column for every number, in brackets. If the table doesn't contain a cause, write 'cause to be confirmed' instead of guessing. Use British English and no dramatic adjectives. I usually ask for two versions: a short one for the sponsor, decisions first, and a fuller one for the team, with actions and owners. If your organisation has approved API access, the lesson text shows the same step as a few lines of Python using the Anthropic SDK, with the model and key set in environment variables.

### Watch me do it: verify and publish

Let me show you the verification step, which is where the project manager earns their keep. I go through the draft line by line. Every number has a bracketed citation, so I check it against the status table: eighteen completed, tick; seven overdue, tick; forecast nine to thirteen weeks, tick. Then causes. The draft says 'delays caused by the vendor'. The table didn't say that; the model inferred it from a label. So I replace it with 'cause to be confirmed with the vendor lead' and send a quick message to find out. Then I add my own judgement: the one thing the sponsor really needs to decide this week. I remove the brackets, add the footer note about AI assistance per our policy, publish, and log the use in the AI register. Total time: about twenty minutes.

### Worked example: a weekly cycle

Here's how it played out for a fictional six-person team running a CRM rollout, with illustrative numbers. Before the pipeline, the weekly report took about two and a half hours: exporting, calculating, formatting and writing. After, about thirty minutes, including a careful review. In the first month, review caught two errors. In week one, the draft rounded a forecast of seven and a half weeks to eight, which the template now forbids. In week three, it inferred a cause from a ticket label that wasn't actually the cause. Both were caught because every number was cited and the rules said not to infer causes. The team also noticed a side benefit: because the script flagged items with no owner or due date, data quality in Jira improved week by week.

### Making it a habit, safely

Once the pipeline works, make it a habit, safely. Schedule the data pull and metric calculation to run automatically early each week, so the status table is waiting for you. Keep the drafting and verification steps deliberately manual, at least until you've built confidence, because that's where judgement lives. Version your prompt template, and keep a simple log of the corrections you make each week by type: numbers, causes, tone. If the same correction keeps appearing, change the prompt, not just the output. And review the whole pipeline every quarter with your data protection or information security colleagues: which data it touches, which tools it uses, and whether anything has changed in your organisation's policies or the tool's terms. A small amount of discipline keeps a useful shortcut from becoming an unmanaged risk.

### Common mistakes, recap and try this now

The common mistakes. Letting the model calculate metrics instead of computing them in code. Pasting raw tickets, which may contain personal or confidential information, instead of an aggregated table. Using unapproved tools, or putting API tokens in scripts. And skipping verification because the draft reads well. So, to recap the pipeline: pull the data with Jira's API or an Asana export; compute a small set of defensible metrics in code; draft with an approved AI tool from the verified table only, with citations and a rule against inventing causes; and verify, add your judgement, publish and log. Your try-this-now: run the pipeline once on your own project this week, time each step, and note every correction you make in review.

## Key takeaways

- Compute metrics in code from the tool's data; let the AI draft words only from a verified table.
- Pull Jira Cloud data with the /rest/api/3/search/jql endpoint and token-based pagination, or use an Asana CSV export.
- Keep API tokens in environment variables and send only aggregated, non-personal data to approved AI tools.
- Require a citation for every number and "cause to be confirmed" when the table has no cause.
- Verify, add judgement, publish and record the AI use in the register.

## Try it

Run the pipeline once on your own project: pull or export data, compute the status table, draft with an approved tool, and log every correction you make in review.

- [Previous: Governing AI use in project delivery](https://optimizeall.com/learn/project-management-leadership-with-ai/governing-ai-in-projects)
- [Next: Project leadership in the AI era: capstone](https://optimizeall.com/learn/project-management-leadership-with-ai/ai-era-project-leadership)
- [All lessons of Project Management Leadership with AI](https://optimizeall.com/learn/project-management-leadership-with-ai)
