Aiden automation guide
This guide shows how to drive Aiden workflows and agents from CI, scripts, or backend jobs using the StackGen SDK. Every example uses explicit config (not a dozen environment variables) and is shown in Python and TypeScript.
Authoring vs running
- Create workflows in code with
createAgent/createStage/createWorkflowandclient.aiden.publishWorkflow— see Create a workflow. - Run existing workflows with webhook or Ask journeys below.
Quick links
| Topic | Jump to |
|---|---|
| Compose + publish a workflow | Create a workflow |
| Terms (session, trace, webhook, …) | Glossary |
| Install and connect | Setup |
| FAQ (install, auth, errors, reports) | FAQ |
| Alert → workflow (webhook) | Trigger a workflow |
| Natural language → workflow/agent | Ask |
| Poll until work is ready | Wait for a session |
| Get the markdown report | Download artifacts |
| Runnable scripts | Code samples |
For SRE alerts and investigations see Usage.
Glossary
Plain-language definitions for terms you will see in responses and logs.
| Term | What it means |
|---|---|
| Mothership | Your StackGen cloud host, e.g. https://app.stackgen.com. Do not append /guild in config — the SDK adds product paths. |
| Organization | Your StackGen tenant. It contains one or more workspaces. |
Workspace (workspace_id) |
UUID of your StackGen workspace. Sent as the orgId query parameter on Aiden routes. Formerly org_id in the SDK. |
| API token | Long-lived token starting with stackgen_…. Used to read sessions, poll executions, and download artifacts. |
| Webhook token | Token starting with sg_aios_…. Used only to POST an alert or payload to /webhooks/trigger. Think of it as “ring the doorbell for automation.” |
| Webhook | A configured entry point that maps an incoming payload to a workflow (or agent). Datadog/Grafana/your script POST to it. |
| Workflow | A multi-step automation (skills, tools, stages) registered in Aiden, e.g. incident-triage. |
| Agent | A conversational agent registered in Aiden. Ask can route to an agent when you pin one with entity_refs. |
| Trigger | The first HTTP call that starts work — either webhook POST or Ask start. |
Session (session_id) |
Conversation/workspace id for the run. You need it to list artifacts and continue a chat. |
Trace (trace_id) |
Execution trace id returned by Ask. Poll it until the run finishes. |
| Run / invocation | Webhook-specific ids in the trigger response (webhook_id, invocation_id, run_id) for tracking the invocation. |
| Execution settled | Ask poll is done when execution.status is completed or error and trace_settled is true. |
| Artifact | File produced in the session, usually session-report.md — the triage/RCA write-up. |
entity_refs |
Optional Ask body field that pins a workflow or agent by name so routing is deterministic in CI. |
| Poll | SDK repeatedly GETs an endpoint until a condition is met (session exists, execution settled, artifact listed). Default interval 5s, timeout 30 minutes. |
| LLM provider / LLM model | A configured model backend (OpenAI-compatible, Ollama, …) and the models registered under it. Managed with client.aiden.llm. |
| Knowledge hub | A collection of documents agents can read. Managed with create_knowledge_hub / createKnowledgeHub. |
How it fits together
Two common paths:
flowchart LR
subgraph webhookPath [Webhook path]
A[Your alert or JSON] --> B[POST webhooks/trigger]
B --> C[Workflow runs]
C --> D[session_id]
D --> E[session-report.md]
end
subgraph askPath [Ask path]
F[Natural language message] --> G[POST guild/ask/start]
G --> H[Poll executions/traceId]
H --> I[session_id]
I --> E
end
Webhook path — best when you already have a webhook URL/token (e.g. wired from Datadog) and a structured alert body.
Ask path — best when you only have an API token and want to say “run workflow
X for this incident” in plain language. Pin the workflow with entity_refs in CI.
Setup
Install
pip install stackgen-sdk==0.1.5
npm install stackgen-sdk@0.1.5
Connect
Use three mothership fields everywhere. Add webhook_token only for webhook journeys.
Python
from stackgen import StackgenClient, StackgenConfig
client = StackgenClient(
StackgenConfig(
base_url="https://app.stackgen.com",
api_token="stackgen_…", # stackgen_… from StackGen UI
workspace_id="4f942a41-…", # workspace UUID → orgId
webhook_token="sg_aios_…", # only for webhook trigger
poll_interval_seconds=5,
timeout_seconds=1800, # 30 min default
artifact_name="session-report.md",
output_path="session-report.md",
)
)
TypeScript
import { StackgenClient, StackgenConfig } from "stackgen-sdk";
const client = new StackgenClient(
new StackgenConfig({
baseUrl: "https://app.stackgen.com",
apiToken: "stackgen_…",
workspaceId: "4f942a41-…",
webhookToken: "sg_aios_…", // only for webhook trigger
pollIntervalSeconds: 5,
timeoutSeconds: 1800,
artifactName: "session-report.md",
outputPath: "session-report.md",
}),
);
Optional convenience — three env vars only (STACKGEN_URL, STACKGEN_TOKEN,
STACKGEN_WORKSPACE_ID), then set webhook token in code:
from dataclasses import replace
from stackgen import StackgenClient, StackgenConfig
client = StackgenClient(
replace(StackgenConfig.from_env(), webhook_token="sg_aios_…")
)
const base = StackgenConfig.fromEnv();
const client = new StackgenClient(
new StackgenConfig({ ...base, webhookToken: "sg_aios_…" }),
);
Which token when?
| Action | Token |
|---|---|
| POST webhook trigger | webhook_token / webhookToken |
| Poll webhook runs, list/download artifacts | api_token / apiToken |
| Ask start, poll execution, artifacts | api_token / apiToken only |
Journey 1: Trigger a workflow via webhook
Use this when a webhook is already configured to start a workflow (for example
incident-triage) and you have the sg_aios_… token.
What happens
- SDK POSTs your alert text/JSON to
/guild/api/v1/webhooks/trigger?orgId=… - Aiden acknowledges immediately (default HTTP
202; configurable viaresponse_status/response_headerson create — see Webhook acknowledgement) and starts the target workflow asynchronously. Newer motherships may returnsession_idon that acknowledgement body; otherwise the SDK pollsGET /webhooks/{webhook_id}/runs/{invocation_id}untilsession_idis set. The same sequence is in the webhook session artifact script. - SDK waits until
session-report.md(or your artifact name) appears - SDK downloads the file to
output_path
For queue + scheduler architectures, use stateless methods (trigger_webhook, wait_for_webhook_session, …) — see Async webhook CI.
A provider that fires one webhook for many event types (GitHub pull-request
opens, edits, comments, review requests) can skip the ones that should not
start work at all. Set filter_cel on create or update so a nonmatching
delivery is acknowledged with no run, no invocation row, and no AI-query
charge — see Webhook condition (filter_cel).
One call (recommended)
Python
from pathlib import Path
payload = Path("alert.json").read_text(encoding="utf-8")
# Or plain text: payload = "P1 | checkout-api error rate above SLO"
result = client.aiden.run_webhook_and_download_report(payload)
print("webhook_id", result.webhook_id)
print("session_id", result.session_id)
print("report", result.output_path)
TypeScript
import { readFileSync } from "node:fs";
const payload = readFileSync("alert.json", "utf8");
const result = await client.aiden.runWebhookAndDownloadReport(payload);
console.log("webhookId", result.webhookId);
console.log("sessionId", result.sessionId);
console.log("report", result.outputPath);
Equivalent curl
The SDK does the same as:
curl -X POST \
"https://app.stackgen.com/guild/api/v1/webhooks/trigger?orgId=<workspace-uuid>" \
-H "Authorization: Bearer sg_aios_…" \
-H "Content-Type: text/plain" \
-d @alert.txt
Then the SDK uses your API token to wait for the session artifact and download it.
Trigger only, wait for session yourself
If you only need session_id and will download the report later, see
Webhook → session only
on the code samples page. The step-by-step flow:
- POST the webhook (JSON or plain text)
- Read
session_idfrom the 202 body when present, or poll run detail withwait_for_webhook_session - Optionally wait for and download the report
Journey 2: Start work or an agent with Ask
Use Ask when you have only the API token and want to send a natural-language
task. In CI, always pin the workflow or agent with entity_refs so routing is
predictable.
What happens
- SDK POSTs to
/guild/api/v1/guild/ask/start?orgId=…withmessage(+ optionalentity_refs) - Response includes
trace_idand usuallysession_id - SDK polls
/guild/api/v1/executions/{traceId}until status is terminal andtrace_settled - SDK waits for the session artifact and downloads it
There is no SSE in the SDK — polling only, which works in CI and locked-down networks.
One call — workflow pinned (recommended for CI)
Python
result = client.aiden.run_ask_and_download_artifact(
message="Run triage for checkout CPU alert",
entity_refs=[{"name": "incident-triage", "type": "workflow"}],
artifact_name="session-report.md",
output_path="session-report.md",
)
print("trace_id", result.trace_id)
print("session_id", result.session_id)
print("plan", result.plan)
print("report", result.output_path)
TypeScript
const result = await client.aiden.runAskAndDownloadArtifact({
message: "Run triage for checkout CPU alert",
entityRefs: [{ name: "incident-triage", type: "workflow" }],
artifactName: "session-report.md",
outputPath: "session-report.md",
});
console.log("traceId", result.traceId);
console.log("sessionId", result.sessionId);
console.log("plan", result.plan);
console.log("report", result.outputPath);
Pin an agent instead of a workflow
entity_refs=[{"name": "my-sre-agent", "type": "agent"}]
entityRefs: [{ name: "my-sre-agent", type: "agent" }]
Valid type values: workflow, agent, integration, knowledge, or any.
Agent query without pinning (interactive only)
Omitting entity_refs lets Aiden choose among candidates. That is fine for
exploratory chat; for pipelines, always pin a workflow or agent.
Mid-turn follow-up (action: steer)
Incidents rarely arrive as one perfect prompt. You start Ask, then remember the
deploy window or get a better log line in Slack. Send another message on the
same session_id while the turn is still running. When that turn takes it,
the reply includes action: "steer" and the running trace_id. You do not get a
second parallel investigation.
Use is_steer_response / isSteerResponse, then wait on that trace_id.
Full sample and why you want it: Ask mid-turn steer.
Waiting for a session
A session is created when Aiden starts handling your request. You need
session_id to fetch artifacts and to continue a conversation.
When do you get session_id?
| Path | When |
|---|---|
| Webhook trigger | In the POST response |
| Ask start | In the start response; execution poll is for completion, not discovery |
Ask — step by step (start → wait → optional download)
Advanced control when you want to branch between “started” and “finished”:
Python
start = client.aiden.start_ask(
"Run triage for checkout-api error rate alert",
entity_refs=[{"name": "incident-triage", "type": "workflow"}],
mode="plan", # optional: "plan" | "simple"
)
trace_id = start["trace_id"]
session_id = start.get("session_id")
print("started", trace_id, session_id)
# Block until execution is finished (HTTP poll)
trace = client.aiden.wait_for_execution(trace_id)
session_id = session_id or trace.get("session_id")
print("settled", trace["execution"]["status"], session_id)
# Or wait on the execution subscribe stream (reconnects on drop)
done = client.aiden.wait_for_subscribe_complete(trace_id)
assert done.ok
# Live chat UI: yield text / tool events until RUN_FINISHED
# for ev in client.aiden.stream_execution_events(trace_id): ...
TypeScript
const start = await client.aiden.startAsk(
"Run triage for checkout-api error rate alert",
{
entityRefs: [{ name: "incident-triage", type: "workflow" }],
},
);
const traceId = String(start.trace_id ?? "");
let sessionId = String(start.session_id ?? "");
console.log("started", traceId, sessionId);
const trace = await client.aiden.waitForExecution(traceId);
if (!sessionId) {
sessionId = String(trace.session_id ?? "");
}
console.log("settled", (trace.execution as { status?: string }).status, sessionId);
const done = await client.aiden.waitForSubscribeComplete(traceId);
if (!done.ok) {
throw new Error("subscribe did not complete");
}
// Live chat UI: for await (const ev of client.aiden.streamExecutionEvents(traceId)) …
If start_ask returns inputs_required, the workflow needs more fields — pass them
via inputs={...} / inputs: { ... } or fix your message; the SDK raises
StackgenError on the one-shot helper.
To list and download every session artifact after subscribe completes (operator notes, Keep a Changelog markdown, multi-file triage), see Ask → session artifacts. To print reply text and tool calls as they arrive, see Stream agent chat.
Webhook — step by step
See Webhook → session → artifact for the full scripts, including webhook-wait-session.py. Minimal CLI shape:
export WEBHOOK_TOKEN='sg_aios_…'
python webhook-wait-session.py \
--base-url https://app.stackgen.com \
--api-token stackgen_… \
--org-id 4f942a41-… \
--json-body \
--query-file alert.json
# prints session_id=… when ready
Download an execution debug ZIP
When you need the same triage bundle as Activity / watch (DAG, subscribe replay,
optional judge), call download_execution_debug_zip / downloadExecutionDebugZip
with the execution trace_id:
path = client.aiden.download_execution_debug_zip(
trace_id,
"execution-debug.zip",
# timeout_seconds=180, # optional abort for a hung cold export
)
Sample: Ask → debug ZIP.
Download session artifacts
After Ask finishes, download every named note with
download_session_artifacts / downloadSessionArtifacts, or keep the
single-file helpers when you already know the name. Full journeys still
download session-report.md by default. Customize:
client.aiden.run_ask_and_download_artifact(
"…",
entity_refs=[{"name": "incident-triage", "type": "workflow"}],
artifact_name="session-report.md",
output_path="./out/report.md",
)
await client.aiden.runAskAndDownloadArtifact({
message: "…",
entityRefs: [{ name: "incident-triage", type: "workflow" }],
artifactName: "session-report.md",
outputPath: "./out/report.md",
});
Artifact name matching is case-insensitive.
When no artifact file is present, export the session write-up:
Python
export = client.aiden.export_session(session_id, parts="report")
TypeScript
await client.aiden.exportSession(sessionId, { parts: "report" });
Search or cancel long runs from a scheduler:
Python
client.aiden.list_sessions(q="corr-123")
client.aiden.terminate_session(session_id, reason="scheduler timeout")
client.aiden.list_executions(session_id=session_id)
TypeScript
await client.aiden.listSessions({ q: "corr-123" });
await client.aiden.terminateSession(sessionId, { reason: "scheduler timeout" });
await client.aiden.listExecutions({ session_id: sessionId });
For SRE Copilot investigate-from-alert (alert already in the SRE app), see SRE → investigate alert and Automation surface.
Runnable examples
Full scripts with syntax highlighting are on the Code samples page. Copy them from the browser.
| Sample | Language | What it demonstrates |
|---|---|---|
| Webhook → session (step-by-step) | Python | Trigger → read session_id → optional download |
| Webhook → report (one call) | TypeScript | One-call webhook journey |
| Ask → report (CLI) | Python | Ask → poll → download |
| Ask → execution only | Python / TypeScript | Start + wait for execution |
| Ask mid-turn steer | Python / TypeScript | Follow-up with action=steer |
| Chat subscriptions | Python / TypeScript | Create / toggle / delete |
Errors and timeouts
| Error | Meaning |
|---|---|
StackgenError |
Business failure (bad trigger, execution error, missing inputs, …) |
TimeoutError |
Poll exceeded timeout_seconds (session, execution, or artifact) |
HttpError |
HTTP status failure (check token and workspace_id) |
GET polling retries transient 429 and any 5xx. Trigger POST is not
retried automatically (avoid duplicate runs).
FAQ
Common questions about installation, tokens, webhooks, inputs/outputs, retries, and operational limits are answered in the dedicated FAQ (Aiden + SRE use cases).
Quick picks
| Question | Answer |
|---|---|
| Webhook or Ask? | Webhook when you have sg_aios_… and alert payloads; Ask when you have only an API token and a message (pin with entity_refs in CI). |
| Why two tokens? | Webhook token starts automation; API token reads sessions and artifacts. |
| Live progress? | Polling only in this SDK — use the StackGen UI for live traces. |
| Full API list? | Product map |