Provider Desk API
Everything the web app does over the model is one HTTP call. Base URL https://api.skillsafe.ai/v1/app-api. Every request carries Authorization: Bearer <token> and every response uses the same envelope.
The response envelope
Success is {"ok": true, "data": {...}}. Failure is {"ok": false, "error": {"code": "...", "message": "...", "details": {...}}}. Always branch on ok, never on the HTTP status alone.
| Code | HTTP | What it means here |
|---|---|---|
UNAUTHORIZED | 401 | Missing, malformed or expired token. Mint a new one on the token page. |
PAYMENT_REQUIRED | 402 | Balance below min_credits for this lane. Call /estimate first and top up. |
VALIDATION_ERROR | 400 | The input object is the wrong shape — usually a missing source or an unknown task. |
RATE_LIMITED | 429 | Back off and retry. Do not tight-loop. |
NOT_FOUND | 404 | Wrong job id, or a job that belongs to another subject. |
INTERNAL | 500 | Retry once with the same idempotency key. |
The task field comes first
Provider Desk is one app with four lanes over one work object — the Go source of a provider resource. Every request must set task; it selects the lane, the prompt section, the output body shape and the price. If task is missing the model picks the closest lane and reports lane_inferred: true — usable, but never what you want from a script.
task | What that lane returns |
|---|---|
schema | Audit the resource: an attribute-by-attribute verdict, a lifecycle table, the breaking changes a fix would introduce, an ordered plan, and the corrected .go file. |
tests | Design the acceptance suite: the test plan, the attribute assertions, a CheckDestroy, the import step, HCL fixtures and the complete _test.go. |
docs | Write the registry page: front matter, prose, the Required / Optional / Read-Only schema table, worked examples and the import section, as Markdown. |
release | Clear the release: the semver decision, the changelog entry, a pre-publish checklist, release-build issues, the registry manifest and the signing status. |
Input fields
Taken from readForm() in app.js — this is exactly what the web app sends.
| Field | Type | Required | Notes |
|---|---|---|---|
task | string | yes | One of schema, tests, docs, release. |
source | string | yes | The pasted Go. Separate multiple files with a // file: name.go line. Clipped from the middle at 52,000 characters, both ends kept. |
notes | string | no | Free text about the repository and the API. The release lane leans on it heavily — module path, current version, build tooling — because none of that is in the Go. |
framework | string | no | plugin-framework, sdkv2, mixed or unknown. |
prescan | object | no | What the browser reader found. Omit it and the model simply has fewer facts — but then coverage_check comes back empty, because there are no flags to reconcile. |
retry_note | string | no | Sent by the web app only on the one reformat retry, when the first reply did not parse. It is an instruction to the model to answer again with nothing but the single JSON object the contract requires, naming the lane it was asked for. A first attempt never carries it, and it changes no part of the output contract. |
clip_note | string | no | Send it when you clipped source yourself, so the model writes around the gap rather than inventing across it. |
Step 1 — get a token
Open the token page, reveal your token and copy the shell export. It is the same token the web app holds in this browser, so a script and the page share one identity, one balance and one history. Keep it out of source control — export it as PROVIDER_DESK_TOKEN and read it from there, the way every sample below does.
Step 2 — confirm the session and the balance
GET /me is free. It tells you whether the token is a personal or a guest subject and how many credits it can spend.
curl -sS "https://api.skillsafe.ai/v1/app-api/me" \
-H "Authorization: Bearer $PROVIDER_DESK_TOKEN"import json, urllib.request, os
TOKEN = os.environ.get("PROVIDER_DESK_TOKEN", "YOUR_TOKEN")
req = urllib.request.Request("https://api.skillsafe.ai/v1/app-api/me",
headers={"Authorization": "Bearer " + TOKEN})
print(json.load(urllib.request.urlopen(req)))const TOKEN = "YOUR_TOKEN";
const res = await fetch("https://api.skillsafe.ai/v1/app-api/me", {
headers: { Authorization: `Bearer ${TOKEN}` }
});
console.log(await res.json());package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
token := os.Getenv("PROVIDER_DESK_TOKEN")
req, _ := http.NewRequest("GET", "https://api.skillsafe.ai/v1/app-api/me", nil)
req.Header.Set("Authorization", "Bearer "+token)
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}import java.net.URI;
import java.net.http.*;
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://api.skillsafe.ai/v1/app-api/me"))
.header("Authorization", "Bearer YOUR_TOKEN")
.build();
System.out.println(client.send(req, HttpResponse.BodyHandlers.ofString()).body());require 'net/http'
require 'uri'
uri = URI('https://api.skillsafe.ai/v1/app-api/me')
req = Net::HTTP::Get.new(uri)
req['Authorization'] = 'Bearer YOUR_TOKEN'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.body<?php
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/me");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_TOKEN"],
]);
echo curl_exec($ch);using System.Net.Http;
using System.Net.Http.Headers;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN");
Console.WriteLine(await http.GetStringAsync("https://api.skillsafe.ai/v1/app-api/me"));Step 3 — estimate before you spend
POST /estimate is free and charges nothing. It returns model, model_alias, markup_bps, hold_credits and min_credits. The hold differs per lane, so estimate the lane you are about to run — never reuse another lane’s number.
curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/estimate" \
-H "Authorization: Bearer $PROVIDER_DESK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework"
}'import json, urllib.request, os
TOKEN = os.environ.get("PROVIDER_DESK_TOKEN", "YOUR_TOKEN")
body = {
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework"
}
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/estimate",
data=json.dumps(body).encode(),
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json"},
method="POST")
print(json.load(urllib.request.urlopen(req)))const TOKEN = "YOUR_TOKEN";
const res = await fetch("https://api.skillsafe.ai/v1/app-api/estimate", {
method: "POST",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework"
})
});
console.log(await res.json());package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
token := os.Getenv("PROVIDER_DESK_TOKEN")
body := []byte(`{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework"
}`)
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/estimate", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}import java.net.URI;
import java.net.http.*;
var body = """
{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework"
}
""";
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://api.skillsafe.ai/v1/app-api/estimate"))
.header("Authorization", "Bearer YOUR_TOKEN")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
System.out.println(client.send(req, HttpResponse.BodyHandlers.ofString()).body());require 'net/http'
require 'uri'
require 'json'
uri = URI('https://api.skillsafe.ai/v1/app-api/estimate')
req = Net::HTTP::Post.new(uri)
req['Authorization'] = 'Bearer YOUR_TOKEN'
req['Content-Type'] = 'application/json'
req.body = {
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework"
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.body<?php
$body = <<<'JSON'
{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework"
}
JSON;
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/estimate");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_TOKEN", "Content-Type: application/json"],
]);
echo curl_exec($ch);using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
var body = @"{
""task"": ""schema"",
""source"": ""package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\""id\""`\n\tName types.String `tfsdk:\""name\""`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\""id\"": schema.StringAttribute{Computed: true},\n\t\t\t\""name\"": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}"",
""notes"": """",
""framework"": ""plugin-framework""
}";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN");
var content = new StringContent(body, Encoding.UTF8, "application/json");
var res = await http.PostAsync("https://api.skillsafe.ai/v1/app-api/estimate", content);
Console.WriteLine(await res.Content.ReadAsStringAsync());Step 4 — run a lane
POST /run is metered and returns {"job_id": "..."}. Always send Idempotency-Key, and derive it from the lane plus a hash of the input plus an attempt counter — two lanes over the same file are two distinct runs and must not collide on one key. Below is the schema lane in eight languages; a worked request for the other three lanes follows it. The only field that has to change is task — and, on the release lane, notes, which that lane cannot do without.
curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/run" \
-H "Authorization: Bearer $PROVIDER_DESK_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: provider-desk:schema:1f9k2m:a1" \
-d '{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}'import json, urllib.request, os
TOKEN = os.environ.get("PROVIDER_DESK_TOKEN", "YOUR_TOKEN")
body = {
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/run",
data=json.dumps(body).encode(),
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json",
"Idempotency-Key": "provider-desk:schema:1f9k2m:a1"},
method="POST")
print(json.load(urllib.request.urlopen(req)))const TOKEN = "YOUR_TOKEN";
const res = await fetch("https://api.skillsafe.ai/v1/app-api/run", {
method: "POST",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
"Idempotency-Key": "provider-desk:schema:1f9k2m:a1"
},
body: JSON.stringify({
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
})
});
console.log(await res.json());package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
token := os.Getenv("PROVIDER_DESK_TOKEN")
body := []byte(`{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}`)
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/run", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "provider-desk:schema:1f9k2m:a1")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}import java.net.URI;
import java.net.http.*;
var body = """
{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}
""";
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://api.skillsafe.ai/v1/app-api/run"))
.header("Authorization", "Bearer YOUR_TOKEN")
.header("Content-Type", "application/json")
.header("Idempotency-Key", "provider-desk:schema:1f9k2m:a1")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
System.out.println(client.send(req, HttpResponse.BodyHandlers.ofString()).body());require 'net/http'
require 'uri'
require 'json'
uri = URI('https://api.skillsafe.ai/v1/app-api/run')
req = Net::HTTP::Post.new(uri)
req['Authorization'] = 'Bearer YOUR_TOKEN'
req['Content-Type'] = 'application/json'
req['Idempotency-Key'] = 'provider-desk:schema:1f9k2m:a1'
req.body = {
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.body<?php
$body = <<<'JSON'
{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}
JSON;
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/run");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_TOKEN", "Content-Type: application/json", "Idempotency-Key: provider-desk:schema:1f9k2m:a1"],
]);
echo curl_exec($ch);using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
var body = @"{
""task"": ""schema"",
""source"": ""package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\""id\""`\n\tName types.String `tfsdk:\""name\""`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\""id\"": schema.StringAttribute{Computed: true},\n\t\t\t\""name\"": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}"",
""notes"": """",
""framework"": ""plugin-framework"",
""prescan"": {
""summary"": {
""framework"": ""plugin-framework"",
""kind"": ""resource"",
""type_name"": ""widget"",
""attributes"": 2
},
""flags"": [
{
""id"": ""PD01"",
""severity"": ""critical"",
""label"": ""Attributes are both Required and Computed"",
""line"": 12,
""detail"": ""name"",
""why"": ""The framework rejects this combination at startup.""
}
],
""checks"": [
{
""id"": ""C10"",
""label"": ""Attribute semantics legal"",
""status"": ""fail"",
""detail"": ""1 attribute declares an illegal combination""
}
],
""resources"": [
{
""id"": ""R2"",
""label"": ""Terraform type suffix _widget""
}
]
}
}";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN");
http.DefaultRequestHeaders.Add("Idempotency-Key", "provider-desk:schema:1f9k2m:a1");
var content = new StringContent(body, Encoding.UTF8, "application/json");
var res = await http.PostAsync("https://api.skillsafe.ai/v1/app-api/run", content);
Console.WriteLine(await res.Content.ReadAsStringAsync());The same call on the other three lanes
Every language sample above sends the same JSON body, so only the body is shown here. The release lane is the one that genuinely needs notes: the module path, the released version and the existing build tooling are simply not in the Go, and without them the lane can only answer unknown.
task: "release" — with the repository facts the Go cannot carry
curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/run" \
-H "Authorization: Bearer $PROVIDER_DESK_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: provider-desk:release:1f9k2m:a1" \
-d '{
"task": "release",
"source": "package provider\n\nfunc (r *WidgetResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {\n\tresp.TypeName = req.ProviderTypeName + \"_widget\"\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true},\n\t\t\t\"region\": schema.StringAttribute{Required: true},\n\t\t},\n\t}\n}",
"notes": "Module path github.com/examplecloud/terraform-provider-examplecloud. Currently released as v1.3.2. This change makes region Required; it was Optional in v1.3.2. We build with GoReleaser 2 from .goreleaser.yml and sign SHA256SUMS with the GPG key already registered with the registry. terraform-registry-manifest.json exists and declares protocol 6. There is no docs/resources/widget.md yet.",
"framework": "plugin-framework"
}'
That notes block is what turns the checklist from eight unknown rows into a judgement: the version decision becomes major and names region as the attribute that drove it, and the missing documentation page is a fail rather than a shrug.
task: "docs" — the registry page for the same resource
curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/run" \
-H "Authorization: Bearer $PROVIDER_DESK_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: provider-desk:docs:1f9k2m:a1" \
-d '{
"task": "docs",
"source": "package provider\n\nfunc (r *WidgetResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {\n\tresp.TypeName = req.ProviderTypeName + \"_widget\"\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, MarkdownDescription: \"The name of the widget.\"},\n\t\t\t\"region\": schema.StringAttribute{Required: true},\n\t\t},\n\t}\n}",
"notes": "Provider name examplecloud. Import is by widget id.",
"framework": "plugin-framework"
}'
The docs lane answers with body.schema_table split into Required / Optional / Read-Only and artifact.kind: "markdown" holding the whole page. region has no MarkdownDescription in that paste, so it also comes back as a finding: the generator would otherwise publish an empty description cell.
task: "tests" — the acceptance suite for the same resource
curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/run" \
-H "Authorization: Bearer $PROVIDER_DESK_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: provider-desk:tests:1f9k2m:a1" \
-d '{
"task": "tests",
"source": "package provider\n\nfunc (r *WidgetResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {\n\tvar m WidgetResourceModel\n\tresp.Diagnostics.Append(req.State.Get(ctx, &m)...)\n\tw, err := r.client.GetWidget(ctx, m.ID.ValueString())\n\tif err != nil {\n\t\tresp.Diagnostics.AddError(\"read failed\", err.Error())\n\t\treturn\n\t}\n\tm.Name = types.StringValue(w.Name)\n\tresp.Diagnostics.Append(resp.State.Set(ctx, &m)...)\n}",
"notes": "CheckDestroy should use r.client.GetWidget and treat a not-found error as proof of destruction.",
"framework": "plugin-framework"
}'
Step 5 — poll the job
GET /jobs/{job_id} until status is terminal. The model reply is the string at data.output.output; parse it as JSON.
curl -sS "https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID" \
-H "Authorization: Bearer $PROVIDER_DESK_TOKEN"import json, urllib.request, os
TOKEN = os.environ.get("PROVIDER_DESK_TOKEN", "YOUR_TOKEN")
req = urllib.request.Request("https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID",
headers={"Authorization": "Bearer " + TOKEN})
print(json.load(urllib.request.urlopen(req)))const TOKEN = "YOUR_TOKEN";
const res = await fetch("https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID", {
headers: { Authorization: `Bearer ${TOKEN}` }
});
console.log(await res.json());package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
token := os.Getenv("PROVIDER_DESK_TOKEN")
req, _ := http.NewRequest("GET", "https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID", nil)
req.Header.Set("Authorization", "Bearer "+token)
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}import java.net.URI;
import java.net.http.*;
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID"))
.header("Authorization", "Bearer YOUR_TOKEN")
.build();
System.out.println(client.send(req, HttpResponse.BodyHandlers.ofString()).body());require 'net/http'
require 'uri'
uri = URI('https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID')
req = Net::HTTP::Get.new(uri)
req['Authorization'] = 'Bearer YOUR_TOKEN'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.body<?php
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_TOKEN"],
]);
echo curl_exec($ch);using System.Net.Http;
using System.Net.Http.Headers;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN");
Console.WriteLine(await http.GetStringAsync("https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID"));Step 6 — or stream it
POST /run-stream is the same call over server-sent events. Deltas arrive as they are produced; the app uses them to advance its progress card on the section headings appearing in the stream.
curl -sS -N -X POST "https://api.skillsafe.ai/v1/app-api/run-stream" \
-H "Authorization: Bearer $PROVIDER_DESK_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: provider-desk:schema:1f9k2m:a1" \
-d '{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}'import json, urllib.request, os
TOKEN = os.environ.get("PROVIDER_DESK_TOKEN", "YOUR_TOKEN")
body = {
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/run-stream",
data=json.dumps(body).encode(),
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json",
"Idempotency-Key": "provider-desk:schema:1f9k2m:a1"},
method="POST")
print(json.load(urllib.request.urlopen(req)))const TOKEN = "YOUR_TOKEN";
const res = await fetch("https://api.skillsafe.ai/v1/app-api/run-stream", {
method: "POST",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
"Idempotency-Key": "provider-desk:schema:1f9k2m:a1"
},
body: JSON.stringify({
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
})
});
console.log(await res.json());package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
token := os.Getenv("PROVIDER_DESK_TOKEN")
body := []byte(`{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}`)
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/run-stream", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "provider-desk:schema:1f9k2m:a1")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}import java.net.URI;
import java.net.http.*;
var body = """
{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}
""";
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://api.skillsafe.ai/v1/app-api/run-stream"))
.header("Authorization", "Bearer YOUR_TOKEN")
.header("Content-Type", "application/json")
.header("Idempotency-Key", "provider-desk:schema:1f9k2m:a1")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
System.out.println(client.send(req, HttpResponse.BodyHandlers.ofString()).body());require 'net/http'
require 'uri'
require 'json'
uri = URI('https://api.skillsafe.ai/v1/app-api/run-stream')
req = Net::HTTP::Post.new(uri)
req['Authorization'] = 'Bearer YOUR_TOKEN'
req['Content-Type'] = 'application/json'
req['Idempotency-Key'] = 'provider-desk:schema:1f9k2m:a1'
req.body = {
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.body<?php
$body = <<<'JSON'
{
"task": "schema",
"source": "package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\"id\"`\n\tName types.String `tfsdk:\"name\"`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\"id\": schema.StringAttribute{Computed: true},\n\t\t\t\"name\": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}",
"notes": "",
"framework": "plugin-framework",
"prescan": {
"summary": {
"framework": "plugin-framework",
"kind": "resource",
"type_name": "widget",
"attributes": 2
},
"flags": [
{
"id": "PD01",
"severity": "critical",
"label": "Attributes are both Required and Computed",
"line": 12,
"detail": "name",
"why": "The framework rejects this combination at startup."
}
],
"checks": [
{
"id": "C10",
"label": "Attribute semantics legal",
"status": "fail",
"detail": "1 attribute declares an illegal combination"
}
],
"resources": [
{
"id": "R2",
"label": "Terraform type suffix _widget"
}
]
}
}
JSON;
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/run-stream");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_TOKEN", "Content-Type: application/json", "Idempotency-Key: provider-desk:schema:1f9k2m:a1"],
]);
echo curl_exec($ch);using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
var body = @"{
""task"": ""schema"",
""source"": ""package provider\n\ntype WidgetResourceModel struct {\n\tID types.String `tfsdk:\""id\""`\n\tName types.String `tfsdk:\""name\""`\n}\n\nfunc (r *WidgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {\n\tresp.Schema = schema.Schema{\n\t\tAttributes: map[string]schema.Attribute{\n\t\t\t\""id\"": schema.StringAttribute{Computed: true},\n\t\t\t\""name\"": schema.StringAttribute{Required: true, Computed: true},\n\t\t},\n\t}\n}"",
""notes"": """",
""framework"": ""plugin-framework"",
""prescan"": {
""summary"": {
""framework"": ""plugin-framework"",
""kind"": ""resource"",
""type_name"": ""widget"",
""attributes"": 2
},
""flags"": [
{
""id"": ""PD01"",
""severity"": ""critical"",
""label"": ""Attributes are both Required and Computed"",
""line"": 12,
""detail"": ""name"",
""why"": ""The framework rejects this combination at startup.""
}
],
""checks"": [
{
""id"": ""C10"",
""label"": ""Attribute semantics legal"",
""status"": ""fail"",
""detail"": ""1 attribute declares an illegal combination""
}
],
""resources"": [
{
""id"": ""R2"",
""label"": ""Terraform type suffix _widget""
}
]
}
}";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN");
http.DefaultRequestHeaders.Add("Idempotency-Key", "provider-desk:schema:1f9k2m:a1");
var content = new StringContent(body, Encoding.UTF8, "application/json");
var res = await http.PostAsync("https://api.skillsafe.ai/v1/app-api/run-stream", content);
Console.WriteLine(await res.Content.ReadAsStringAsync());The output contract
One JSON object. The envelope is identical on all four lanes; only body differs. These are the fields normalize() in app.js actually reads — anything else you send is preserved but never rendered.
| Field | Type | Meaning |
|---|---|---|
lane | string | The lane that answered. Always one of the four ids; compare it against the task you sent. |
lane_inferred | boolean | true when task was missing or unrecognised and the model picked a lane. A script should treat this as an error. |
title | string | A short human title naming the resource. |
posture | string | registry-ready, fix-first or not-shippable — about the resource, not about this lane's output. |
verdict | string | One paragraph you could paste into a pull request. |
framework | string | The framework the model concluded you are on. |
resource_type | string | The Terraform type suffix without the provider prefix — the widget in examplecloud_widget. |
summary | string | Two or three sentences of context. |
assumptions | string[] | What the model had to assume because the paste did not say. |
open_questions | string[] | What it would ask before merging. |
findings | object[] | id, title, severity (critical/high/medium/low), area, file, line, evidence, why, fix, fix_code. Sorted by severity by the client. |
coverage_check | object[] | One entry per prescan.flags[].id you sent: flag_id, status (confirmed/set-aside/superseded), finding_id, note. A flag with no entry is shown to the user as ignored. |
artifact | object | kind (none/go/markdown/hcl/yaml), filename, content. |
next_lane | object | lane and reason — the pipeline is schema → tests → docs → release. |
body | object | The only per-lane part. Shapes below. |
One worked body per lane
task: "schema"
{
"attribute_review": [{ "name": "api_token", "verdict": "fail", "issue": "...", "corrected": "..." }],
"lifecycle": [{ "method": "Read", "status": "fail", "note": "..." }],
"breaking_changes": ["..."],
"hardening_plan": [{ "step": "...", "why": "...", "code": "..." }]
}
task: "tests"
{
"test_plan": [{ "name": "TestAccWidgetResource_basic", "purpose": "...", "steps": ["..."] }],
"checks": [{ "attribute": "name", "check_func": "resource.TestCheckResourceAttr(...)", "note": "..." }],
"destroy_check": { "approach": "...", "code": "..." },
"import_step": { "enabled": true, "id_format": "...", "verify_ignore": ["..."] },
"fixtures": [{ "name": "step 1 - create", "hcl": "..." }]
}
task: "docs"
{
"front_matter": { "page_title": "...", "subcategory": "", "description": "..." },
"sections": [{ "heading": "Example Usage", "markdown": "..." }],
"schema_table": [{ "name": "name", "kind": "String", "requirement": "Required", "description": "..." }],
"examples": [{ "filename": "examples/resources/.../resource.tf", "hcl": "..." }],
"import_doc": { "supported": true, "id_format": "...", "command": "..." }
}
task: "release"
{
"semver": { "level": "minor", "version": "1.4.0", "reason": "..." },
"changelog": [{ "type": "FEATURES", "text": "..." }],
"checklist": [{ "item": "...", "status": "pass", "note": "...", "fix": "..." }],
"goreleaser": { "issues": ["..."], "snippet": "..." },
"registry_manifest": { "required": true, "snippet": "..." },
"signing": { "status": "pass", "note": "..." }
}
Notes that will save you an hour
- Send the
prescanobject or expect an emptycoverage_check. The reconciliation the app shows exists only because the client sent numbered flags for the model to answer. With no flags there is nothing to reconcile, and the model is not being held to anything. Idempotency-Keymust include the lane. The web app usesslug:lane:hash:attempt. Reusing one key across two lanes returns the first lane's answer for both.- Estimate the lane you are running. Prompts and output caps differ per lane, so the hold does too.
- Check
laneagainst thetaskyou sent. If they differ, orlane_inferredistrue, yourtaskvalue never arrived. - A
truncated: truejob is a real answer, cut short. Render what parsed and tell the user to top up rather than discarding it. - Line numbers are relative to the
sourceyou sent, including any// file:marker lines.