Automation surface (Ask + SRE)
Backend and CI patterns for starting Aiden work, polling until it settles, and fetching the write-up. Two start paths share the same poll and download helpers.
Prefer complete recipes: Async Ask worker · Async webhook worker · Ask → export report
flowchart LR
worker[Your worker]
worker -->|"Ask or webhook"| aiden[Aiden]
worker -->|"list then investigate"| sre[SRE Copilot]
sre --> aiden
aiden --> report[session-report.md or export]
sre --> rca[Investigation RCA]
When to use which path
| Job | Start with | Fetch |
|---|---|---|
| Free-text page or incident RCA | start_ask / run_ask_and_download_artifact |
session-report.md or export_session |
| Closure / postmortem markdown | Ask with a pinned closure workflow | artifact or export report part |
| Alert already in SRE Copilot | list_alerts → investigate_alert |
get_investigation RCA; optional Aiden session file |
Do not call vendor query APIs through the StackGen SDK. Observability tools stay as integrations the agent uses inside the run.
Path A — Ask (pinned workflow)
from stackgen import StackgenClient, StackgenConfig
client = StackgenClient(
StackgenConfig(
base_url="https://app.stackgen.com",
api_token="stackgen_…",
workspace_id="<workspace-uuid>",
)
)
result = client.aiden.run_ask_and_download_artifact(
"Investigate the checkout CPU alert in prod",
entity_refs=[{"name": "incident-triage", "type": "workflow"}],
source_metadata={"correlation_id": "corr-123", "incident_id": "INC-1001"},
artifact_name="session-report.md",
)
print(result.session_id, result.output_path)import { StackgenClient, StackgenConfig } from "stackgen-sdk";
const client = new StackgenClient(
new StackgenConfig({
baseUrl: "https://app.stackgen.com",
apiToken: "stackgen_…",
workspaceId: "<workspace-uuid>",
}),
);
const result = await client.aiden.runAskAndDownloadArtifact({
message: "Investigate the checkout CPU alert in prod",
entityRefs: [{ name: "incident-triage", type: "workflow" }],
sourceMetadata: { correlation_id: "corr-123", incident_id: "INC-1001" },
artifactName: "session-report.md",
});
console.log(result.sessionId, result.outputPath);result, err := client.Aiden.RunAskAndDownloadArtifact(ctx,
"Investigate the checkout CPU alert in prod",
aiden.StartAskOptions{
EntityRefs: []aiden.EntityRef{{Name: "incident-triage", Type: "workflow"}},
SourceMetadata: map[string]string{
"correlation_id": "corr-123",
"incident_id": "INC-1001",
},
},
"session-report.md",
"session-report.md",
)
if err != nil { return err }
fmt.Println(result.SessionID, result.OutputPath)
return nilIf the workflow does not write an artifact, export the session write-up:
export = client.aiden.export_session(result.session_id, parts="report")
for part in export.get("parts") or []:
if part.get("kind") == "report":
print(part.get("content"))const exported = await client.aiden.exportSession(result.sessionId, {
parts: "report",
});
for (const part of (exported.parts as Array<Record<string, unknown>>) ?? []) {
if (part.kind === "report") {
console.log(part.content);
}
}exported, err := client.Aiden.ExportSession(ctx, result.SessionID, "report", "json")
if err != nil { return err }
parts, _ := exported["parts"].([]any)
for _, raw := range parts {
part, _ := raw.(map[string]any)
if part["kind"] == "report" {
fmt.Println(part["content"])
}
}
return nilLookup and cancel helpers for queue workers:
detail = client.aiden.get_session("sess-…")
sessions = client.aiden.list_sessions(q="corr-123")
client.aiden.terminate_session("sess-…", reason="scheduler timeout")
runs = client.aiden.list_executions(session_id="sess-…")const detail = await client.aiden.getSession("sess-…");
const sessions = await client.aiden.listSessions({ q: "corr-123" });
await client.aiden.terminateSession("sess-…", { reason: "scheduler timeout" });
const runs = await client.aiden.listExecutions({ session_id: "sess-…" });detail, err := client.Aiden.GetSession(ctx, "sess-…")
if err != nil { return err }
sessions, err := client.Aiden.ListSessions(ctx, url.Values{"q": {"corr-123"}})
if err != nil { return err }
if _, err = client.Aiden.TerminateSessionReason(ctx, "sess-…", "scheduler timeout"); err != nil {
return err
}
runs, err := client.Aiden.ListExecutions(ctx, url.Values{"session_id": {"sess-…"}})
_, _ = detail, sessions
return errPath B — SRE investigate alert
Requires the SRE app installed and the alert row present.
alerts = client.sre.list_alerts(status="active", q="checkout CPU")
alert_id = alerts["items"][0]["id"]
started = client.sre.investigate_alert(alert_id)
inv = client.sre.get_investigation(started["investigation"]["id"])
# poll until inv["status"] is terminal, then read RCA / result_summary
session_id = inv.get("guild_session_id")const alerts = await client.sre.listAlerts({ status: "active", q: "checkout CPU" });
const items = (alerts.items as Array<Record<string, unknown>>) ?? [];
const alertId = String(items[0].id);
const started = await client.sre.investigateAlert(alertId);
const investigation = started.investigation as Record<string, unknown>;
const inv = await client.sre.getInvestigation(String(investigation.id));
// poll until inv.status is terminal, then read RCA / result_summary
const sessionId = inv.guild_session_id;alerts, err := client.SRE.ListAlerts(ctx, map[string]string{"status": "active", "q": "checkout CPU"})
if err != nil { return err }
items := alerts.(map[string]any)["items"].([]any)
alertID := fmt.Sprint(items[0].(map[string]any)["id"])
started, err := client.SRE.InvestigateAlert(ctx, alertID, nil)
if err != nil { return err }
investigation := started.(map[string]any)["investigation"].(map[string]any)
inv, err := client.SRE.GetInvestigation(ctx, fmt.Sprint(investigation["id"]))
if err != nil { return err }
sessionID := inv.(map[string]any)["guild_session_id"]
_ = sessionID
return nilFull sample: SRE → investigate alert.
Tokens
| Credential | Use |
|---|---|
API token (stackgen_…) |
Ask, sessions, artifacts, export, terminate, SRE |
Webhook token (sg_aios_…) |
trigger_webhook only |
workspace_id |
Workspace UUID sent as orgId on Aiden routes |