Receber por email
← Voltar para o catálogo

seam-probe

Use this skill to test, validate, fuzz, or debug a process boundary ("seam") that exposes itself as an FFI dynamic library or a Unix-domain socket — for example probing a Rust runtime hosted in a Swift or Electron app via its C ABI, or sending crafted length-prefixed frames to a daemon's UDS endpoint. The skill teaches how to drive the probe from the CLI, capture both the probe's NDJSON output AND

11estrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add johnkozaris/jko-claude-plugins

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/seam-probe/svg)](https://www.skillteca.com.br/skills/seam-probe)

Skills relacionadas

Ver todas de Desenvolvimento →

Alerta por categoria

Receba novas skills de Desenvolvimento toda segunda

1 email curto, só com as skills novas de Desenvolvimento. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

seam-probe

seam-probe is a generic NDJSON probe for embedded-runtime seams. It ships zero app-specific knowledge. Everything app-specific is expressed in a small JSON manifest that the user (or you) writes and hands to the binary.

There are two real seams in this skill's world:

| Seam | What it is | Probe mode | | --------------- | ----------------------------------------------------- | --------------- | | FFI dylib | dlopen + extern "C" entry points + callback struct | seam-probe ffi | | UDS endpoint | Unix-domain socket carrying length-prefixed frames | seam-probe socket |

Plus two utility modes that need no manifest:

| Utility | What it does | | ---------------- | ----------------------------------------------------- | | inspect | Dump exported symbols of a dylib (Mach-O / ELF / PE) | | vocab | Print the stdin/stdout NDJSON contract verbatim |

Scope: what counts as a "seam"

The probe handles dynamically-loaded native code (FFI mode) and Unix-domain sockets carrying byte frames (socket mode). Concretely in scope:

  • .dylib (Mach-O), .so (ELF), .dll (PE) loaded via dlopen /

LoadLibrary. The library must export an extern "C" lifecycle function and accept a plain C-ABI callback struct.

  • Unix-domain stream sockets with be32 / be64 / varint framing,

or no framing at all.

Out of scope today (would need probe extensions, not just a manifest):

  • Statically-linked Rust crates (crate-type = ["staticlib"],

produces .a/.lib). Static archives have no dynamic load surface — they're meant to be linked at build time. The probe cannot load them. Tell the user to expose a cdylib alongside their static target for probing; see "Preparing a Rust crate for probing" below. This is a build-config change only — no code changes, no impact on production distribution.

  • UniFFI crates. UniFFI produces a cdylib that is dlopen-able,

but exports use UniFFI's own wire format: every call goes through RustBuffer (a (ptr, len, capacity) struct) with a RustCallStatus out-parameter, and arguments are serialised via UniFFI's binary format. The probe's three callback signature kinds (json / json_with_sid / raw_with_seq) don't model this. For UniFFI-exposed crates use uniffi-bindgen to generate a Swift / Kotlin / Python / Ruby binding and test through that. Probing UniFFI directly would require the probe to read the *.uniffi.json metadata and implement the FFI converter protocol — significant scope creep.

  • TCP sockets — same framing logic would apply, but the binary

has no --tcp host:port mode yet. For loopback testing of a TCP service, fall back to nc / socat / websocat.

  • Subprocess + stdio — driving a CLI that reads NDJSON on stdin

and emits responses on stdout. Common for "headless mode" Rust runtimes. For this, just use shell pipes + tee.

  • Wasm modules — wasmtime / wasmer calling exports with

import shims. Different ABI from C; not implemented.

  • gRPC, D-Bus, HTTP, WebSocket — use grpcurl, busctl, curl,

websocat respectively.

  • Kernel modules, JNI, Python C API — out of scope.

If the user wants to probe one of the out-of-scope surfaces, say so and suggest the right tool rather than forcing a fit.

Preparing a Rust crate for probing

If the user's crate is staticlib-only (or rlib-only, or it's a binary crate with no library target), it's not loadable by the probe. Have them add a cdylib output to their Cargo.toml. This does not change what they ship — they can keep their existing target and add cdylib alongside:

[lib]
crate-type = ["cdylib", "staticlib"]   # or just ["cdylib"] for probing only

After cargo build --release, the cdylib lands at:

| Platform | Path | | --- | --- | | macOS | target/release/lib<crate_name>.dylib | | Linux | target/release/lib<crate_name>.so | | Windows| target/release/<crate_name>.dll |

The crate must also actually expose its surface as extern "C":

#[unsafe(no_mangle)]
pub extern "C" fn foo_start(cb: *const FooCallbacks) -> i32 { /* … */ }

#[unsafe(no_mangle)]
pub extern "C" fn foo_stop() { /* … */ }

If the crate uses mangle or extern "Rust", it's not probe-able even as a cdylib — symbols won't be resolvable by name. Internal Rust APIs need to be wrapped with a thin C-ABI shim module. This is a small one-time cost; the user can gate it behind a feature flag (#[cfg(feature = "probe")]) so it doesn't pollute production.

Generating a C header at build time with cbindgen is strongly recommended — the manifest's callback_struct[] field order has to match the C struct exactly, and the header is the source of truth.

Preflight

seam-probe vocab >/dev/null

If this errors with seam-probe is not built, the SessionStart hook either hasn't finished yet (fresh install or plugin update — wait a moment and retry) or it failed. Tell the user to run /seam-probe-setup for verbose recovery output.

If the command runs but a flag in this skill is missing or behaviour disagrees with the docs, stop and ask the user to update the plugin. Do not guess around missing features.

When to reach for which mode

  1. You don't know what the dylib exports → start with seam-probe inspect.
  2. You have an unfamiliar dylib but know its callback contract → write

a manifest, then seam-probe ffi.

  1. You have a UDS endpoint but don't know the framing → try

--framing be32 first (most common); fall back to --framing none and inspect raw bytes if framing is wrong.

  1. You forget the NDJSON contract → seam-probe vocab.
  2. You're hunting a bug, panic, or hang → run the probe with stderr

captured (FFI) or with the SUT log tailed (socket) and correlate the two streams. See "Read both streams" below.

How to invoke the CLI

The probe is one binary with four subcommands. Always separate stdout (NDJSON) from stderr (probe diagnostics + anything the loaded library prints). The two streams answer different questions and you usually need both.

inspect — list a dylib's exports

seam-probe inspect --lib /path/to/libfoo.dylib

No manifest, no stdin. Emits one symbol line per export plus a summary line. Use it before writing a manifest, or to confirm a build actually exposes what you expect.

ffi — drive a dylib via a manifest

seam-probe ffi \
    --lib /path/to/libfoo.dylib \
    --manifest /path/to/foo.manifest.json \
    [--no-events] \
    [--shutdown-grace-ms 2000]

| Flag | When to use it | | --- | --- | | --lib | Required. Shared library to dlopen. | | --manifest | Required. JSON describing the FFI surface (references/manifest-schema.md). | | --no-events | Mute callback event/json_with_sid/raw_with_seq lines. Use when you only care about send/call return codes. | | --shutdown-grace-ms | Time to wait between stop and process exit. Bump it (e.g. 5000) if the runtime has worker threads that need longer to drain. Symptom of "too short": probe hangs at exit, or the runtime later complains about lost messages. |

Read input from stdin (one JSON op per line). Heredoc is the cleanest way to drive a deterministic sequence:

seam-probe ffi --lib ./libfoo.dylib --manifest /tmp/foo.manifest.json \
    > /tmp/probe.ndjson 2> /tmp/sut.stderr <<'EOF'
{"op":"call","name":"start_session","arg":"sess-1"}
{"op":"send","lane":"events","payload":{"hello":"world"}}
{"op":"sleep_ms","ms":500}
{"op":"stop"}
EOF
echo "exit=$?"

socket — drive a UDS endpoint

seam-probe socket \
    --path /tmp/foo.sock \
    [--framing be32|be64|varint|none] \
    [--no-events]

| Flag | When to use it | | --- | --- | | --path | Required. The Unix socket the SU

Compartilhar X LinkedIn