DEV Community

Nexus Labs
Nexus Labs

Posted on

From Scraps to Structure: Reliably Extracting Actions with My GPT for Asana

Meeting notes. We all take them. We all hate trying to turn those free-form scribbles, bullet points, and tangents into actionable tasks. For years, I've dreamt of a world where action items and responsible parties magically appear in my Asana projects. So, naturally, when Custom GPTs landed, I thought, "This is it! My salvation!"

Spoiler alert: It wasn't that simple. Not at first.

The Dream and the Messy Reality

My initial idea was straightforward: feed my custom GPT meeting notes, have it spit out action items, and then push those to Asana. I was running on GPT-4 Turbo, optimistic and ready to reclaim my precious manual data entry time. My instructions to the GPT were initially pretty high-level: "Identify action items and the person or team responsible for each, then format them as a JSON array." Sounded reasonable, right?

Oh, how naive I was.

The output was, to put it mildly, wildly inconsistent. One moment I'd get {"task": "Follow up on Q3 report", "who": "Sarah (Sales)"}, the next it would be {"action": "Check Q3 numbers", "owner": "Sales Team"}. Sometimes it would just summarize the entire meeting, completely ignoring my request for actions. Other times, it would invent owners or teams that weren't even mentioned in the notes. It was like a game of whack-a-mole, but every mole was a different JSON schema violation or a hallucinated detail. I spent a solid 10 hours over a week just trying to refine the prompt, thinking the magic was all in the instruction tuning.

I tried:

  1. More specific prompt language: "Always output JSON. Keys must be action_description, responsible_team, responsible_person. If no person is named, use null for responsible_person." Better, but still flaky. Sometimes responsible_person would be "The Marketing Team" even if responsible_team was "Marketing". Redundant, incorrect, or just plain weird.
  2. Providing examples: I'd give it 2-3 perfect JSON examples based on mock notes. This helped a little, but it often felt like the GPT would follow the structure but still mess up the content or infer too much.
  3. Threatening and cajoling: "THIS IS CRITICAL. DO NOT DEVIATE." (Yes, I actually tried that. No, it didn't work. Turns out LLMs don't respond well to emotional blackmail.)

The biggest problem was reliability. I needed consistent output, not just generally correct output. Pushing inconsistent data to Asana was just creating a different kind of mess.

What Actually Fixed It: System Message + A Tiny Python Script

The turning point came when I stopped viewing the custom GPT as the entire solution and started seeing it as a powerful, but fallible, first pass. The actual fix involved two key components working in tandem:

  1. An extremely strict system message (not just user prompt) enforcing a JSON schema. I moved a lot of my detailed instructions into the system message of my custom GPT (or if you're using the API directly, the system role). This is crucial because it sets the fundamental operating instructions for the model. My system message now includes something like this:

    You are an expert assistant for extracting structured action items from free-form meeting notes.
    Your sole output must be a JSON array of objects, where each object represents an action item.
    Each object MUST have the following keys:

    • task_description: (string) A concise description of the task.
    • responsible_team: (string) The name of the team responsible. If no team is explicitly mentioned, infer from context but prefer general terms (e.g., "Engineering", "Sales", "Marketing", "Product").
    • responsible_person: (string | null) The full name of the individual responsible. If no specific person is mentioned, set this to null.

    Strictly adhere to this JSON structure. Do NOT include any conversational text before or after the JSON. If no action items are found, return an empty array [].

    This, combined with some user-level instructions to process the specific meeting notes, started getting me much closer.

  2. A small, opinionated Python script for validation and Asana pushing. This was the true game-changer. I wrote a script that does a few critical things:

*   **JSON Schema Validation**: It takes the GPT's output and uses jsonschema to ensure it *actually* conforms to the expected structure. If it doesn't, it flags it immediately.
*   **Responsible Party Mapping**: Asana doesn't just take arbitrary team names or person names; it needs IDs. My script has a dictionary mapping common team names (e.g., "Marketing") to Asana project IDs or custom field values, and more importantly, person_name (e.g., "Jane Doe") to Asana assignee user IDs (like 1234567890). If the GPT output for responsible_person doesn't match an entry in my lookup, the script either flags it or attempts to fuzzy-match.
*   **Asana API Integration**: Once validated and mapped, the script uses the asana Python client to create tasks, assign them, and add them to the correct projects. It handles edge cases, like tasks without a specific person (assigning them to the team's project lead, for instance).
Enter fullscreen mode Exit fullscreen mode

Here’s a simplified snippet of what the validation part looks like:

python
import json
from jsonschema import validate, ValidationError

... (GPT output fetching)

gpt_output_json = json.loads(gpt_raw_output)

schema = {
"type": "array",
"items": {
"type": "object",
"properties": {
"task_description": {"type": "string"},
"responsible_team": {"type": "string"},
"responsible_person": {"type": ["string", "null"]}
},
"required": ["task_description", "responsible_team", "responsible_person"]
}
}

try:
validate(instance=gpt_output_json, schema=schema)
print("GPT output valid!")
# Proceed with mapping and Asana push
except ValidationError as e:
print(f"Validation error: {e.message}")
# Log error, send notification, or trigger manual review

This two-pronged approach changed everything. The custom GPT now provides highly structured JSON, and my Python script acts as a robust safety net, catching any deviations, normalizing data, and handling the nitty-gritty of the Asana API. I’m now getting about 95% accurate extractions that flow smoothly into Asana, saving me roughly two hours a week that I used to spend translating notes into tasks. The remaining 5% are easy manual tweaks on the few items the script flags.

It wasn't just about prompt engineering; it was about building a reliable system around the AI. The GPT is incredibly powerful for parsing natural language, but a little bit of deterministic code for validation and integration makes it truly production-ready.

Top comments (0)