online / endpoints 62 / categories 10 / rate 60/min/ip /

GET /.well-known/agent-skills/index.json

GET /.well-known/agent-skills/index.json

Agent Skills Discovery v0.2.0 index control. References a single skill stub at not.catastrophic.io/.well-known/agent-skills/echo.json so the discovery chain resolves end-to-end. The sha256 digest is all-zeros — obviously fake but format-correct, same pattern AASA and assetlinks use on this host. Build against this baseline; flip hostname to chaos to exercise the failure modes.

expect: 200 OK, Content-Type: application/json. $schema present, single skill entry whose url resolves to a valid skill document on this same host. X-Chaos-Origin: control. X-Chaos-Counterpart points at chaos.catastrophic.io/.well-known/agent-skills/index.json.

bash
curl -i 'https://not.catastrophic.io/.well-known/agent-skills/index.json'
# The canonical agent-skills consumer flow: fetch index, walk skills,
# fetch each, verify sha256. Most modes break a different step.
import urllib.request, json, hashlib

index = json.loads(urllib.request.urlopen("https://not.catastrophic.io/.well-known/agent-skills/index.json").read())
print("$schema:", index.get("$schema"))
for skill in index.get("skills", []):
    print(f"\n  name:   {skill['name']}")
    try:
        body = urllib.request.urlopen(skill["url"]).read()
        actual = hashlib.sha256(body).hexdigest()
        ok = actual == skill["sha256"]
        print(f"  url:    {skill['url']}")
        print(f"  digest: declared={skill['sha256']}")
        print(f"          actual  ={actual}  {'OK' if ok else 'MISMATCH'}")
    except Exception as e:
        print(f"  url:    {skill['url']}  -> {type(e).__name__}: {e}")
const res = await fetch("https://not.catastrophic.io/.well-known/agent-skills/index.json");
const index = await res.json();
console.log("Mode:", res.headers.get("X-Chaos-Skills-Mode"));
console.log("$schema:", index.$schema);
for (const skill of index.skills || []) {
    try {
        const r = await fetch(skill.url);
        const bytes = new Uint8Array(await r.arrayBuffer());
        const digest = await crypto.subtle.digest("SHA-256", bytes);
        const actual = [...new Uint8Array(digest)].map(b => b.toString(16).padStart(2, "0")).join("");
        console.log(`${skill.name}: ${actual === skill.sha256 ? "OK" : "MISMATCH"}`);
    } catch (e) {
        console.log(`${skill.name}: fetch failed - ${e.message}`);
    }
}
package main

import (
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

type Skill struct {
    Name, URL, SHA256 string
}
type Index struct {
    Schema string  `json:"$schema"`
    Skills []Skill `json:"skills"`
}

func main() {
    resp, _ := http.Get("https://not.catastrophic.io/.well-known/agent-skills/index.json")
    defer resp.Body.Close()
    var idx Index
    json.NewDecoder(resp.Body).Decode(&idx)
    fmt.Println("$schema:", idx.Schema)
    for _, s := range idx.Skills {
        r, err := http.Get(s.URL)
        if err != nil { fmt.Printf("%s: fetch failed - %v\n", s.Name, err); continue }
        body, _ := io.ReadAll(r.Body); r.Body.Close()
        sum := sha256.Sum256(body)
        actual := hex.EncodeToString(sum[:])
        status := "OK"
        if actual != s.SHA256 { status = "MISMATCH" }
        fmt.Printf("%s: %s\n", s.Name, status)
    }
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
//             sha2 = "0.10"
use sha2::{Digest, Sha256};
fn main() -> Result<(), Box> {
    let index: serde_json::Value = reqwest::blocking::get("https://not.catastrophic.io/.well-known/agent-skills/index.json")?.json()?;
    for skill in index["skills"].as_array().unwrap_or(&vec![]) {
        let url = skill["url"].as_str().unwrap();
        let declared = skill["sha256"].as_str().unwrap();
        let body = reqwest::blocking::get(url)?.bytes()?;
        let actual = format!("{:x}", Sha256::digest(&body));
        println!("{}: {}", skill["name"], if actual == declared { "OK" } else { "MISMATCH" });
    }
    Ok(())
}
import com.fasterxml.jackson.databind.*;
import java.net.URI;
import java.net.http.*;
import java.security.MessageDigest;

public class AgentSkillsIndex {
    public static void main(String[] args) throws Exception {
        var client = HttpClient.newHttpClient();
        var req = HttpRequest.newBuilder(URI.create("https://not.catastrophic.io/.well-known/agent-skills/index.json")).build();
        var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
        var idx = new ObjectMapper().readTree(resp.body());
        for (var skill : idx.path("skills")) {
            var body = client.send(
                HttpRequest.newBuilder(URI.create(skill.get("url").asText())).build(),
                HttpResponse.BodyHandlers.ofByteArray()
            ).body();
            var actual = bytesToHex(MessageDigest.getInstance("SHA-256").digest(body));
            System.out.println(skill.get("name").asText() + ": " +
                (actual.equals(skill.get("sha256").asText()) ? "OK" : "MISMATCH"));
        }
    }
    static String bytesToHex(byte[] b) {
        var sb = new StringBuilder();
        for (byte x : b) sb.append(String.format("%02x", x));
        return sb.toString();
    }
}
using System.Security.Cryptography;
using System.Text.Json;
using var client = new HttpClient();
var raw = await client.GetStringAsync("https://not.catastrophic.io/.well-known/agent-skills/index.json");
using var idx = JsonDocument.Parse(raw);
foreach (var skill in idx.RootElement.GetProperty("skills").EnumerateArray()) {
    var url = skill.GetProperty("url").GetString();
    var declared = skill.GetProperty("sha256").GetString();
    var body = await client.GetByteArrayAsync(url);
    var actual = Convert.ToHexString(SHA256.HashData(body)).ToLowerInvariant();
    Console.WriteLine($"{skill.GetProperty("name")}: {(actual == declared ? "OK" : "MISMATCH")}");
}
require "net/http"
require "json"
require "digest"

index = JSON.parse(Net::HTTP.get(URI("https://not.catastrophic.io/.well-known/agent-skills/index.json")))
puts "$schema: #{index['$schema']}"
(index["skills"] || []).each do |skill|
    body = Net::HTTP.get(URI(skill["url"])) rescue nil
    if body
        actual = Digest::SHA256.hexdigest(body)
        puts "#{skill['name']}: #{actual == skill['sha256'] ? 'OK' : 'MISMATCH'}"
    else
        puts "#{skill['name']}: fetch failed"
    end
end
$idx = (Invoke-RestMethod -Uri 'https://not.catastrophic.io/.well-known/agent-skills/index.json')
$idx.'$schema'
foreach ($skill in $idx.skills) {
    try {
        $body = (Invoke-WebRequest -Uri $skill.url).Content
        $bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
        $hash = [System.Security.Cryptography.SHA256]::Create().ComputeHash($bytes)
        $actual = [BitConverter]::ToString($hash).Replace('-','').ToLower()
        "$($skill.name): " + ($(if ($actual -eq $skill.sha256) { 'OK' } else { 'MISMATCH' }))
    } catch {
        "$($skill.name): fetch failed - $($_.Exception.Message)"
    }
}