vt-c-project-status-sync¶
Multi-source project status sync. Aggregates project signals from Open Brain (Sally.io meeting transcripts uploaded throughout the week) and an optional PO-Weekly transcript, then writes confirmed status updates to Asana.
Plugin: project-updates
Category: Other
Command: /vt-c-project-status-sync
Project Status Sync¶
Aggregate project status signals from multiple sources (Open Brain, Granola, PO-Weekly transcript) and write confirmed updates to Asana. Open Brain is the primary source — Sally.io meeting transcripts are uploaded via webhook throughout the week. Granola provides direct access to meeting transcripts not yet captured by Open Brain. The PO-Weekly transcript is the final confirmation/override layer.
Signal Model¶
All sources produce normalized ProjectSignals:
{
project_name: str, # spoken or referenced name
content: str, # relevant text (quote, summary, observation)
source_type: str, # "po-weekly" | "open-brain" | "granola" | "granola-transcript"
source_detail: str, # e.g. "Sally.io meeting 2026-03-24" or "Open Brain thought #42"
signal_strength: str, # "strong" (PO-Weekly) | "medium" (other sources)
date: str # ISO date of the source
}
Prerequisites¶
-
Load project config from
If config does not exist, this seeds it from Asana API (requiresTOOLKIT_ROOT/configs/project-config.yaml:ASANA_PAT). -
Build the project lookup list from config: for each project, collect
asana_gid,asana_name,short_name, and allaliases. -
Resolve optional PO-Weekly transcript argument:
- If a path was provided as argument: validate it exists
- If no argument: that's fine — Open Brain signals are the primary source
-
If the user explicitly wants transcript-only mode: suggest
/vt-c-project-updatesinstead -
Staleness guard: For each project in config, check
last_updateddate. - If a project was updated within the last 3 days:
- PO-Weekly signals (strong) still apply — they always override
- Open Brain / Granola signals (medium) are skipped for this project — prevents duplicate updates from overlapping runs
- Track update timestamps: after a successful Asana write, update
last_updatedin the config YAML
Stage 1: Gather Open Brain Signals¶
Query Open Brain for project-relevant observations from the past 7 days.
For each project in the config:
-
Search using project name and aliases:
Filter results to the last 7 days. -
For each relevant thought returned:
-
Create a ProjectSignal:
-
Deduplicate: if the same thought matches multiple aliases for the same project, keep only one signal.
If Open Brain MCP is not available (tools not loaded): display a warning and continue — the skill degrades to transcript-only mode (same as /vt-c-project-updates).
Expected output: List of ProjectSignals from Open Brain, grouped by project.
Stage 1b: Gather Granola Meeting Signals¶
Query Granola for project-relevant meeting content from the past 7 days. This catches meetings not yet uploaded to Open Brain via webhook.
-
List recent meetings:
-
Filter out PO-Weekly meetings (handled separately in Stage 2). Keep all other meetings (SELI, ad-hoc project discussions, client calls, etc.).
-
For each non-PO-Weekly meeting, query for project-relevant content:
-
For each project mentioned in a Granola meeting response:
-
Create a ProjectSignal:
-
Deduplicate against Open Brain signals (Stage 1): if the same meeting content appears in both Open Brain thoughts and Granola results (because Sally.io already uploaded it), keep only one signal — prefer the Open Brain version (it's already in persistent memory).
If Granola MCP is not available (tools not loaded): skip silently. Open Brain signals are the primary source; Granola is supplementary.
Expected output: List of ProjectSignals from Granola meetings, grouped by project.
Stage 2: Parse PO-Weekly Transcript (optional)¶
If a PO-Weekly transcript was provided:
-
Parse the transcript:
-
Segment by project:
-
For each project segment, create a ProjectSignal:
-
Detect "no change" segments: if the segment text contains only phrases like "kein Update", "nichts Neues", "keine Veränderung", "no change", or the segment is very short (< 50 characters) with no status-indicating words — mark the signal as:
If no transcript provided: skip this stage entirely. All status determination will be based on Open Brain signals (Stage 1).
Stage 3: Match Signals to Asana Projects¶
Match all collected ProjectSignals to Asana projects using the existing matching logic:
python3 TOOLKIT_ROOT/scripts/match_projects.py "<all_signals_json>" "TOOLKIT_ROOT/configs/project-config.yaml"
For Open Brain signals that don't match via the script (free-text content rather than structured project blocks), use inline fuzzy matching against the project lookup list built in Stage 0.
Group matched signals by asana_gid. Each project now has 0-N signals from various sources.
Stage 4: Determine Status per Project¶
For each project with matched signals, determine the status update:
Decision matrix:¶
| PO-Weekly signal | Open Brain / Granola signals | Action |
|---|---|---|
| Strong (explicit status) | Any | Use PO-Weekly status. konfidenz: hoch. Other signals enrich was_passiert. |
| Neutral ("no change") | None | Skip — no update needed. |
| Neutral ("no change") | Has signals | Review — PO-Weekly says no change but week had activity. konfidenz: niedrig. |
| Not mentioned | Has signals | Use accumulated signals. konfidenz: mittel. Always goes to review. |
| Not mentioned | None | Skip — project not active this week. |
| No transcript provided | Has signals | Use accumulated signals. konfidenz: mittel. Always goes to review. |
| No transcript provided | None | Skip. |
| Any | Staleness guard triggered (updated < 3 days ago) | Skip medium signals — only PO-Weekly (strong) can override recent updates. |
For each project that needs an update:¶
Use LLM analysis to produce:
- was_passiert: Synthesize what happened from all signals. Cite sources.
- was_kommt: What's coming next (extract from signals or mark "Nicht besprochen").
- status_farbe: One of planmaessig, gefaehrdet, unplanmaessig, zurueckgestellt, erledigt, verworfen
- konfidenz: hoch, mittel, or niedrig (per decision matrix above)
- konfidenz_grund: Why this confidence level — which sources contributed
- quellen: List of source attributions ("PO-Weekly 2026-03-27", "Sally.io meeting 2026-03-24", etc.)
Confidence cap: Non-PO-Weekly signals can never exceed konfidenz: mittel.
Only PO-Weekly with explicit status discussion can reach konfidenz: hoch.
Stage 5: Interactive Review¶
Present status updates for user review, grouped by confidence:
5a. Auto-apply high-confidence updates¶
Display count: "N projects with high-confidence updates (PO-Weekly confirmed) — auto-applying." List project names and proposed status colors for transparency.
5b. Review medium/low-confidence updates¶
For each konfidenz: mittel or niedrig update, present via AskUserQuestion:
Project: {project_name}
Status: {status_farbe} ({mapped Asana color})
Sources: {quellen list}
Was passiert:
{was_passiert}
Was kommt:
{was_kommt}
Confidence: {konfidenz} — {konfidenz_grund}
Options: Confirm / Edit / Skip
- Confirm: Accept as-is
- Edit: User provides corrected status, text, or both
- Skip: Don't create status update for this project
5c. Skipped projects summary¶
Display: "N projects skipped (no change / not discussed)." Ask: "Want to manually add a status update for any of these?" with project list.
Stage 6: Write to Asana¶
Write confirmed status updates to Asana.
Preferred method: Use asana_create_project_status MCP tool if available:
asana_create_project_status(
project_gid: "{asana_gid}",
text: "{was_passiert}\n\nNächste Schritte:\n{was_kommt}",
color: "{mapped_asana_color}",
title: "Status Update {today}"
)
Fallback: If MCP tool is not available, use the Python script:
This requiresASANA_PAT environment variable.
Status color mapping (German → Asana MCP color / REST API status_type):
- planmaessig → green / on_track
- gefaehrdet → yellow / at_risk
- unplanmaessig → red / off_track
- zurueckgestellt → blue / on_hold
- erledigt → complete / complete
- verworfen → red / missed
After each successful write, update last_updated for that project in TOOLKIT_ROOT/configs/project-config.yaml to today's date (staleness guard for future runs).
Stage 7: Report¶
Display summary report:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Project Status Sync — {date}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Sources:
Open Brain signals: {N} thoughts across {M} projects
Granola meetings: {G} meetings queried, {H} with project signals
PO-Weekly transcript: {provided/not provided}
Results:
{X} updates auto-applied (high confidence, PO-Weekly confirmed)
{Y} updates reviewed and confirmed
{Z} updates skipped by user
{W} projects not discussed (no signals)
{E} updates failed (see errors below)
{S} projects skipped by staleness guard (updated < 3 days ago)
Signal sources per project:
{project_name}: PO-Weekly + Sally.io 3/24, 3/26
{project_name}: Open Brain (2 thoughts) + Granola (SELI 3/25)
{project_name}: Granola only (client call 3/23)
...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
If a PO-Weekly transcript was provided: archive it to 02-Knowledge/04-Dokumente/ with date prefix.
Open Brain capture (optional)¶
If capture_thought MCP tool is available: