
Sf Ai Agentforce Observability
Debug Salesforce Agentforce sessions by reconstructing message timelines from STDM parquet exports and tracing failed agent steps in production-like orgs.
Overview
sf-ai-agentforce-observability is an agent skill most often used in Operate (also Build agent-tooling, Ship testing) that reconstructs Agentforce session timelines from STDM data for debugging.
Install
npx skills add https://github.com/jaganpro/sf-skills --skill sf-ai-agentforce-observabilityWhat is this skill?
- Message timeline reconstruction from sessions, interactions, steps, and messages parquet under stdm_data
- CLI flags for --session-id lookup and --list-failed failure triage
- Rich console panels for chronological flow, LLM reasoning, and action I/O
- Workflow assumes local Python, Polars scans, and gitignored capture artifacts (HAR, captures/)
Adoption & trust: 1.1k installs on skills.sh; 418 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Agentforce conversations fail or drift in production and you cannot see chronological messages, steps, and topic transitions in one place.
Who is it for?
Builders with Salesforce Agentforce in market who export or sync STDM telemetry and debug with Python locally.
Skip if: Greenfield agent design with no observability data yet, or teams without Salesforce org access and STDM parquet pipelines.
When should I use this skill?
When debugging Agentforce behavior from STDM parquet, rebuilding message timelines, or triaging failed sessions offline.
What do I get? / Deliverables
You run scripted timeline analysis over parquet STDM exports to pinpoint failed sessions, step ordering, and timing before you change prompts, topics, or actions.
- Chronological message timeline report
- Failed-session listing output
- Step-level reasoning and I/O inspection
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Operate is the primary shelf because the skill analyzes live or captured agent telemetry after deployment, not while designing the agent. Monitoring fits first: message-timeline scripts and STDM entity joins are for observing conversation flow, step timing, and failure modes—not greenfield agent authoring.
Where it fits
Align local stdm_data folder layout and gitignore rules before syncing Agentforce trace exports from your org.
Run --list-failed on staging parquet after a prompt or action change to confirm regressions before promoting.
Drill into a single --session-id when support reports a bad customer-facing agent turn sequence.
Correlate step failures and topic transitions when intermittent tool errors spike in production sessions.
How it compares
Offline trace forensics for Agentforce STDM exports—not a generic LLM eval framework or an MCP server catalog entry.
Common Questions / FAQ
Who is sf-ai-agentforce-observability for?
Indie builders and small teams operating Salesforce Agentforce who need session-level debugging beyond the Builder UI.
When should I use sf-ai-agentforce-observability?
In Operate when monitoring live or recent sessions; after Ship when validating agent behavior from test exports; during Build agent-tooling when wiring trace capture into stdm_data layouts.
Is sf-ai-agentforce-observability safe to install?
Treat captures and parquet as secret-bearing; review the Security Audits panel on this page and never commit HAR, tokens, or org URLs from the skill’s gitignore list.
SKILL.md
READMESKILL.md - Sf Ai Agentforce Observability
# Network capture data — contains session tokens, org URLs, and client-specific content captures/ *.har # Python __pycache__/ *.pyc .trace-venv/ # Dev-only test harness (contains hardcoded org references) scripts/test_v65.py # Output data stdm_data/ *.parquet trace-results/ # Builder URL cache (contains org-specific URLs) .builder-url-cache.json # Debug screenshots debug-*.png #!/usr/bin/env python3 """ Message Timeline Analysis Template Reconstructs conversation timelines for debugging agent behavior. Shows all messages and steps in chronological order for a session. Usage: python3 message-timeline.py --data-dir ./stdm_data --session-id "a0x..." python3 message-timeline.py --data-dir ./stdm_data --list-failed Output includes: - Chronological message flow - Step details (LLM reasoning, action inputs/outputs) - Topic transitions - Timing information """ import argparse import json from pathlib import Path from datetime import datetime import polars as pl from rich.console import Console from rich.panel import Panel from rich.text import Text console = Console() def load_data(data_dir: Path) -> dict: """Load all STDM entities as lazy frames.""" return { "sessions": pl.scan_parquet(data_dir / "sessions" / "**/*.parquet"), "interactions": pl.scan_parquet(data_dir / "interactions" / "**/*.parquet"), "steps": pl.scan_parquet(data_dir / "steps" / "**/*.parquet"), "messages": pl.scan_parquet(data_dir / "messages" / "**/*.parquet"), } def get_session_info(data: dict, session_id: str) -> dict: """Get session metadata.""" session = ( data["sessions"] .filter(pl.col("ssot__Id__c") == session_id) .collect() ) if session.is_empty(): return None row = session.row(0, named=True) return { "id": row.get("ssot__Id__c"), "agent": row.get("ssot__AiAgentApiName__c", "Unknown"), "start": row.get("ssot__StartTimestamp__c"), "end": row.get("ssot__EndTimestamp__c"), "end_type": row.get("ssot__AiAgentSessionEndType__c"), } def get_timeline(data: dict, session_id: str) -> list: """Build chronological timeline of events.""" # Get interactions for this session interactions = ( data["interactions"] .filter(pl.col("ssot__AiAgentSessionId__c") == session_id) .collect() ) interaction_ids = interactions["ssot__Id__c"].to_list() # Get messages messages = ( data["messages"] .filter(pl.col("ssot__AiAgentInteractionId__c").is_in(interaction_ids)) .collect() ) # Get steps steps = ( data["steps"] .filter(pl.col("ssot__AiAgentInteractionId__c").is_in(interaction_ids)) .collect() ) # Build timeline timeline = [] # Add messages for row in messages.iter_rows(named=True): timeline.append({ "type": "message", "timestamp": row.get("ssot__MessageSentTimestamp__c", ""), "interaction_id": row.get("ssot__AiAgentInteractionId__c"), "message_type": row.get("ssot__AiAgentInteractionMessageType__c"), "content": row.get("ssot__ContentText__c", ""), }) # Add steps for row in steps.iter_rows(named=True): timeline.append({ "type": "step", "timestamp": "", # Steps don't have timestamps "interaction_id": row.get("ssot__AiAgentInteractionId__c"), "step_type": row.get("ssot__AiAgentInteractionStepType__c"), "name": row.get("ssot__Name__c"), "input": row.get("ssot__InputValueText__c"), "output": row.get("ssot__OutputValueText__c"), }) # Add interactions (for topic info) for row in interactions.iter_rows(named=True): timeline.append({ "type": "interaction", "timestamp": row.get("ssot__StartTimestamp__c", ""), "interaction_id": row.get("ssot__Id__c"),