DevOps → sync Ops Inbox
Pull tickets from Linear, Jira, or ServiceNow into the Ops Inbox, then list requests with status and matched workflow.
| Step | What the SDK does |
|---|---|
| 1. Sync | sync_requests (ticket pull finishes in this call) |
| 2. List | list_requests |
Classification keeps running after sync. Use
approve request
when a row reaches awaiting_approval.
Request status
| Status | Meaning |
|---|---|
new, triaging |
Still classifying. Use wait_for_triage. |
awaiting_approval |
Ready to approve. |
triage_stopped |
Operator stopped triage. |
approved, executing |
Run in flight. |
completed, deferred, closed |
Settled. |
Minimal
from stackgen import StackgenClient, StackgenConfig
client = StackgenClient(
StackgenConfig(
base_url="https://app.stackgen.com",
api_token="stackgen_…",
workspace_id="<workspace-uuid>",
)
)
print(client.devops.sync_requests())
listed = client.devops.list_requests(page_size=20)
for row in listed.get("requests") or []:
print(row["identifier"], row["status"], row.get("matched_workflow_name"), row["title"])import { StackgenClient, StackgenConfig } from "stackgen-sdk";
const client = new StackgenClient(
new StackgenConfig({
baseUrl: "https://app.stackgen.com",
apiToken: "stackgen_…",
workspaceId: "<workspace-uuid>",
}),
);
console.log(await client.devops.syncRequests());
const listed = (await client.devops.listRequests({ page_size: 20 })) as {
requests?: Array<Record<string, unknown>>;
};
for (const row of listed.requests ?? []) {
console.log(row.identifier, row.status, row.matched_workflow_name, row.title);
}sync, err := client.DevOps.SyncRequests(ctx)
if err != nil { return err }
fmt.Println(sync)
listed, err := client.DevOps.ListRequests(ctx, map[string]string{"page_size": "20"})
if err != nil { return err }
fmt.Println(listed)
return nilHow to run
export STACKGEN_URL=https://app.stackgen.com
export STACKGEN_TOKEN=stackgen_…
export STACKGEN_WORKSPACE_ID=<workspace-uuid>
python examples/devops/sync-inbox.py
# read-only: python examples/devops/sync-inbox.py --no-syncComplete script
- Python:
examples/devops/sync-inbox.py - TypeScript:
examples/devops/sync-inbox.ts - Go:
examples/go/devops/sync-inbox.go
#!/usr/bin/env python3
"""DevOps: sync tickets into the Ops Inbox and list requests.
Documented at:
https://appcd-dev.github.io/stackgen-sdk/code-samples/devops-sync-inbox/
Usage:
python examples/devops/sync-inbox.py --no-sync
python examples/devops/sync-inbox.py
"""
from __future__ import annotations
import argparse
import json
import os
import sys
from stackgen import StackgenClient, StackgenConfig
from stackgen.errors import StackgenError
def _config(args: argparse.Namespace) -> StackgenConfig:
base = (args.base_url or os.environ.get("STACKGEN_URL", "")).strip()
token = (args.api_token or os.environ.get("STACKGEN_TOKEN", "")).strip()
org = (
(args.workspace_id or "").strip()
or os.environ.get("STACKGEN_WORKSPACE_ID", "").strip()
or os.environ.get("STACKGEN_ORG_ID", "").strip()
or os.environ.get("STACKGEN_PROJECT", "").strip()
or os.environ.get("STACKGEN_PROJECT_ID", "").strip()
)
if not base or not token:
raise SystemExit("set STACKGEN_URL / STACKGEN_TOKEN")
return StackgenConfig(base_url=base, api_token=token, workspace_id=org)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--base-url", default="")
parser.add_argument("--api-token", default="")
parser.add_argument("--workspace-id",
"--org-id", default="")
parser.add_argument("--no-sync", action="store_true")
parser.add_argument("--status", default="")
parser.add_argument("--q", default="")
args = parser.parse_args()
client = StackgenClient(_config(args))
if not args.no_sync:
sync = client.devops.sync_requests()
print("sync:", json.dumps(sync, indent=2, default=str))
params: dict = {"page_size": 20}
if args.status:
params["status"] = args.status
if args.q:
params["q"] = args.q
listed = client.devops.list_requests(**params)
print("requests:", json.dumps(listed, indent=2, default=str))
rows = []
if isinstance(listed, dict):
rows = [r for r in (listed.get("requests") or []) if isinstance(r, dict)]
for row in rows:
print(
f"{row.get('identifier')}\t{row.get('status')}\t"
f"{row.get('matched_workflow_name')}\t{row.get('title')}",
file=sys.stderr,
)
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except StackgenError as exc:
print(f"error: {exc}", file=sys.stderr)
if "401" in str(exc):
print(
"hint: DevOps /app/devops routes need the edge to inject workspace identity.",
file=sys.stderr,
)
raise SystemExit(1)/**
* DevOps: sync tickets into the Ops Inbox and list requests.
* Documented at: .../code-samples/devops-sync-inbox/
*
* npx tsx examples/devops/sync-inbox.ts --no-sync
*/
import { parseArgs } from "node:util";
import { StackgenClient, StackgenConfig, StackgenError } from "stackgen-sdk";
function show(label: string, value: unknown): void {
console.log(`${label}:`, JSON.stringify(value, null, 2));
}
async function main(): Promise<number> {
const { values } = parseArgs({
options: {
"base-url": { type: "string", default: "" },
"api-token": { type: "string", default: "" },
"org-id": { type: "string" },
"workspace-id": { type: "string", default: "" },
"no-sync": { type: "boolean", default: false },
status: { type: "string", default: "" },
q: { type: "string", default: "" },
},
});
const baseUrl = (values["base-url"] || process.env.STACKGEN_URL || "").trim();
const apiToken = (values["api-token"] || process.env.STACKGEN_TOKEN || "").trim();
const orgId = (
(values["org-id"] || values["workspace-id"]) ||
process.env.STACKGEN_WORKSPACE_ID ||
process.env.STACKGEN_ORG_ID ||
process.env.STACKGEN_PROJECT ||
process.env.STACKGEN_PROJECT_ID ||
""
).trim();
if (!baseUrl || !apiToken) {
console.error("set STACKGEN_URL / STACKGEN_TOKEN");
return 2;
}
const client = new StackgenClient(new StackgenConfig({ baseUrl, apiToken, workspaceId: orgId }));
if (!values["no-sync"]) {
show("sync", await client.devops.syncRequests());
}
const params: Record<string, unknown> = { page_size: 20 };
if (values.status) params.status = values.status;
if (values.q) params.q = values.q;
const listed = await client.devops.listRequests(params);
show("requests", listed);
return 0;
}
main().then(
(c) => process.exit(c),
(err) => {
console.error(`error: ${err}`);
if (err instanceof StackgenError && String(err).includes("401")) {
console.error("hint: DevOps /app/devops needs edge workspace identity.");
}
process.exit(1);
},
);// Sync tickets into the Ops Inbox and list requests.
//
// go run ./examples/go/devops/sync-inbox.go --no-sync
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"strings"
stackgen "github.com/appcd-dev/stackgen-sdk/clients/go"
)
func envOr(keys ...string) string {
for _, key := range keys {
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
return v
}
}
return ""
}
func main() {
baseURL := flag.String("base-url", "", "")
apiToken := flag.String("api-token", "", "")
orgID := flag.String("workspace-id", "", "Workspace UUID (sent as orgId)")
flag.StringVar(orgID, "org-id", *orgID, "Deprecated: use -workspace-id")
noSync := flag.Bool("no-sync", false, "")
flag.Parse()
base := strings.TrimSpace(*baseURL)
if base == "" {
base = envOr("STACKGEN_URL")
}
token := strings.TrimSpace(*apiToken)
if token == "" {
token = envOr("STACKGEN_TOKEN")
}
org := strings.TrimSpace(*orgID)
if org == "" {
org = envOr("STACKGEN_WORKSPACE_ID", "STACKGEN_ORG_ID", "STACKGEN_PROJECT", "STACKGEN_PROJECT_ID")
}
if base == "" || token == "" {
fmt.Fprintln(os.Stderr, "set STACKGEN_URL and STACKGEN_TOKEN")
os.Exit(2)
}
client, err := stackgen.NewClient(stackgen.Config{BaseURL: base, APIToken: token, WorkspaceID: org})
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
ctx := context.Background()
if !*noSync {
sync, err := client.DevOps.SyncRequests(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
raw, _ := json.MarshalIndent(sync, "", " ")
fmt.Println("sync:", string(raw))
}
listed, err := client.DevOps.ListRequests(ctx, map[string]string{"page_size": "20"})
if err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
raw, _ := json.MarshalIndent(listed, "", " ")
fmt.Println("requests:", string(raw))
}Related: Approve request · Discover workflows