Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Explore Api

ASecurity

Use when exploring an external API/library and recording proof to the Learning Test Registry.

6 stars
0 votes
0 copies
0 views
Added 10/6/2026
ai-agentstypescriptpythongoshellbashnodetestingapi

Works with

cliapi

Security Analysis

A100/100

Scanned 10/6/2026

$npx -y skills add BrennonTWilliams/little-loops --skill explore-api --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Explore Api?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Explore Api
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/brennontwilliams-explore-api/badge)](https://www.skillsdirectory.com/skills/brennontwilliams-explore-api)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: explore-api
description: Use when exploring an external API/library and recording proof to the Learning Test Registry.
argument-hint: "<target> [--assume <claim>]..."
allowed-tools:
  - Read
  - Glob
  - Grep
  - Write
  - Bash(ll-learning-tests:*, mkdir:*, mv:*, python:*, node:*, ls:*, cat:*)
arguments:
  - name: target
    description: Free-text description of the system or API to explore (e.g., "Anthropic SDK streaming").
    required: true
  - name: assume
    description: Pre-seed a claim as assumed-true without running a proof. Repeatable (--assume "<claim>" --assume "<claim>").
    required: false
metadata:
trigger_fixtures:
  should_fire:
    - "explore this external api library and record proof to the learning test registry"
    - "record proof of exploring this external library to the test registry"
  should_not_fire:
    - "prove this unproven internal mechanism with an isolated code spike"
    - "check whether this issue is ready to implement"
---

# Explore API

Guide the agent through the four-phase **Feathers Learning Test** lifecycle for an external system — Ingest → Hypothesize → Execute → Refine — and persist a `LearnTestRecord` to the Learning Test Registry (`.ll/learning-tests/<slug>.md`).

## When to Use

Run when you need to understand how an external API, SDK, or library actually behaves before writing production code that depends on it. Use cases:

- Unsure what events an SDK emits during streaming
- Verifying response shape of a third-party HTTP API
- Confirming the precise return type of a stdlib function
- Building a shared knowledge base so future agents can skip re-discovery (via `ll-learning-tests check "<target>"`)

Do **not** use this skill for testing your own project code — that is what your project's own test suite is for. This skill is for external-system exploration only.

## Arguments

$ARGUMENTS

Parse the input as follows:

```
TARGET = ""           # required positional, first non-flag token
ASSUMED_CLAIMS = []   # repeatable, each --assume "<claim>" appends
AUTO_MODE = false

tokens = shell-tokenize($ARGUMENTS)
i = 0
while i < len(tokens):
    if tokens[i] == "--assume":
        ASSUMED_CLAIMS.append(tokens[i+1])
        i += 2
    elif tokens[i].startswith("--assume="):
        ASSUMED_CLAIMS.append(tokens[i].split("=", 1)[1])
        i += 1
    elif tokens[i] == "--auto" or tokens[i] == "--dangerously-skip-permissions":
        AUTO_MODE = true
        i += 1
    elif TARGET == "":
        TARGET = tokens[i]
        i += 1
    else:
        # extra positional — append to TARGET with a space
        TARGET = TARGET + " " + tokens[i]
        i += 1

if TARGET == "":
    print "Error: target is required"
    print 'Usage: /ll:explore-api "<target>" [--assume "<claim>"]...'
    exit 1
```

Repeatable-flag convention: each `--assume "<claim>"` token-pair contributes one pre-seeded claim. The first non-flag token (or all of them, joined) is the target description.

**Auto-mode detection** (matches the convention in `skills/spike/SKILL.md`, `skills/decide-issue/SKILL.md`, and 8 other skills): set `AUTO_MODE=true` when ANY of the following hold, in addition to the explicit `--auto`/`--dangerously-skip-permissions` flags parsed above —

```bash
if [[ "$ARGUMENTS" == *"--dangerously-skip-permissions"* ]] || [[ -n "${LL_NON_INTERACTIVE:-}" ]] || [[ -n "${DANGEROUSLY_SKIP_PERMISSIONS:-}" ]]; then AUTO_MODE=true; fi
```

`LL_NON_INTERACTIVE` is set unconditionally by every host runner's `build_streaming` for slash-command invocations (`little_loops.host_runner`), so every FSM/loop/`ll-action invoke`-driven call to this skill is `AUTO_MODE=true` without any caller change.

## Compute Slug

The output filename is derived by slugifying the target. The skill must compute the slug to know where to write — and to preview it to the user before doing so.

Algorithm (matches `little_loops.issue_parser.slugify`):

```python
import re
def slugify(text: str) -> str:
    text = re.sub(r"[^\w\s-]", "", text)
    text = re.sub(r"[-\s]+", "-", text)
    return text.strip("-").lower()
```

Example: `"Anthropic SDK streaming"` → `anthropic-sdk-streaming`. Resolved paths:

- Record: `.ll/learning-tests/anthropic-sdk-streaming.md`
- Raw output: `.ll/learning-tests/raw/anthropic-sdk-streaming.txt`

Print the resolved slug before proceeding so the user can correct the target if it slugified unexpectedly.

---

## Phase 1: Ingest

Determine what is already known before generating new hypotheses.

1. **Check the registry first** — query for a prior record of this target:

   ```bash
   ll-learning-tests check "$TARGET"
   ```

   - **Exit 0** (record exists):
     - **If `AUTO_MODE` is true**: do NOT ask a question. Print the existing record for context, then proceed directly to a fresh exploration (Phase 2 onward), overwriting the prior file in Phase 4. A record that already exists is the normal input to a re-prove, not an ambiguity requiring escalation — never use `AskUserQuestion` (or any interactive prompt) in this branch.
     - **If `AUTO_MODE` is false** (interactive human use): print the existing JSON record and ask whether to short-circuit and reuse it, or proceed with a fresh exploration (which will overwrite the prior file). If reusing, report the record and stop.
   - **Exit 1** (no record): proceed.

2. **Read relevant docs and code samples** — use `Read`, `Glob`, and `Grep` to gather:
   - Any vendor docs already mirrored under `docs/` (e.g., from the `scrape-docs` skill)
   - Existing source code in the project that already uses this API
   - Type stubs, dataclasses, or schema files describing the system

3. **Summarize known facts** in 3–5 sentences. This summary scopes the hypotheses generated in Phase 2.

---

## Phase 2: Hypothesize

Generate **3–7 falsifiable claims** about the target's behavior. Each claim must:

- Be a single observable statement (not a compound assertion)
- Be testable by a minimal proof script
- Be specific enough that the script's stdout or exception will clearly prove or refute it

Examples for `"Anthropic SDK streaming"`:

- `streaming events are dicts with a "type" key`
- `the first event has type "message_start"`
- `text deltas arrive on event.delta.text when event.type == "content_block_delta"`
- `the stream emits a final event with type "message_stop"`

Pre-seed any `--assume` claims into the list with `result: untested`. They will appear in the final record but will not be exercised by the proof script unless they happen to be covered by the script's assertions.

Present the full claim list to the user before moving to Phase 3.

---

## Phase 3: Execute

Build and run a minimal proof script that exercises each non-assumed claim.

1. **Pick a language** — Python is the default. Use Node/TypeScript if the target is JS-only.

2. **Scaffold the script to a temp path first** (not directly to `.ll/learning-tests/raw/`), so a failed run does not pollute the registry directory:

   ```bash
   TEMP_DIR=$(mktemp -d)
   SCRIPT="$TEMP_DIR/proof.py"   # or proof.ts / proof.mjs
   OUT="$TEMP_DIR/out.txt"
   ```

   Use the `Write` tool to author the script. Keep it focused — only enough code to surface evidence for the claims, no error handling beyond what is essential.

3. **Run and capture** stdout+stderr together:

   ```bash
   python "$SCRIPT" > "$OUT" 2>&1
   echo "exit: $?"
   ```

4. **On success**, move the raw output into the registry:

   ```bash
   mkdir -p .ll/learning-tests/raw/
   mv "$OUT" ".ll/learning-tests/raw/${SLUG}.txt"
   ```

   `raw_output_path` in the record will be the relative string `".ll/learning-tests/raw/<slug>.txt"`.

5. **On failure** (non-zero exit or no useful output), record the stderr in the raw output anyway — a refuted exploration is still a valuable record. Set the record `status` to `refuted` in Phase 4 if no claims could be proven.

---

## Phase 4: Refine

Diff expected vs actual and emit the registry record.

1. **For each claim**, classify the result:
   - `pass` — the script's output supports the claim
   - `fail` — the script's output contradicts the claim
   - `untested` — the script did not produce evidence for or against this claim (also use for `--assume`-pre-seeded claims that were not exercised)

2. **Determine record status**:
   - `proven` — at least one assertion is `pass`
   - `refuted` — all exercised assertions are `fail` (no passes)
   - `stale` — reserved for `ll-learning-tests mark-stale`; do not set on initial write

3. **Emit the record** with the `Write` tool. The on-disk format (verbatim shape produced by `little_loops.learning_tests.write_record()`):

   ```yaml
   ---
   target: <TARGET verbatim>
   date: '<YYYY-MM-DD today, ISO date>'
   status: proven
   assertions:
   - claim: <claim text>
     result: pass
   - claim: <claim text>
     result: fail
   - claim: <pre-seeded assumed claim>
     result: untested
   raw_output_path: .ll/learning-tests/raw/<slug>.txt
   ---
   ```

   - Two further optional keys, `proven_package` and `proven_version`, are part of the format (ENH-3125) but are **not yours to write**: `ll-learning-tests prove` stamps them deterministically from `importlib.metadata` after this skill returns — but **only when the target's first word, or its longest hyphen prefix (`jinja2-byte-exact` → `jinja2`), names an installed Python distribution**. Standard-library and free-text targets stay unstamped by design, and `prove` prints a note when it skips. Omit the keys regardless — a typed-from-memory version would silently poison version-drift staleness toward "not stale". To make a record version-aware, lead the target with the package name.
   - File body is **empty** — frontmatter fences only, then a single trailing newline.
   - Use single-quoted ISO date (`'2026-05-11'`) to match `yaml.dump` output.
   - Single-quote any `claim` containing ` #` or `: ` (double any inner `'`). Unquoted, YAML reads ` #` as a comment and silently truncates the claim, e.g. `a [[# ... #]] comment` parses as `a [[# ...`.
   - `target` is the original free-text string, not the slug.
   - Write path: `.ll/learning-tests/<slug>.md` (the directory was already ensured to exist by the `mkdir -p .ll/learning-tests/raw/` in Phase 3, but call `mkdir -p .ll/learning-tests/` as well if the raw step was skipped).

4. **Verify** with the registry CLI:

   ```bash
   ll-learning-tests check "$TARGET"
   ```

   Expect exit 0 and a JSON dump matching the record just written.

5. **Report results** to the conversation:

   ```
   ✓ Learning test record written: .ll/learning-tests/<slug>.md
     Status: proven | refuted
     Proven: N
     Refuted: M
     Untested (incl. assumed): K
     Raw output: .ll/learning-tests/raw/<slug>.txt
   ```

   List each claim with its result so the user can scan-read the findings without opening the file.

---

## CLI Surface Reminder

`ll-learning-tests` exposes these subcommands:

| Subcommand | Purpose | Exit |
|---|---|---|
| `check "<target>" [--stale-aware]` | Print JSON record by target name | 0 if found (and not stale, with `--stale-aware`), 1 if missing |
| `list` | Print JSON array of all records | always 0 |
| `mark-stale "<target>"` | Set `status: stale` on an existing record | 0 |
| `orphans [--mark-stale] [--scope DIRS]` | List records for packages no longer imported anywhere in the configured source dirs | 0 if none found (or `--mark-stale` used), 1 if any found |
| `prove "<target>"` | Trigger proving for a target via `ready-to-implement-gate` (no issue file required), print the refreshed record | 0 if proven, 1 if refuted/still missing |

There is intentionally **no `write` subcommand** — record creation is owned by skills/agents (this one and any future variants) so the prompt context can capture the proof reasoning, not just the result. To persist a new record, use the `Write` tool as described in Phase 4. `prove` doesn't bypass this — it drives the same `ready-to-implement-gate` → `/ll:explore-api` path that writes records, it just orchestrates that path for callers that only have a bare target string.

## Examples

```bash
# Explore from scratch
/ll:explore-api "Anthropic SDK streaming"

# Pre-seed assumed claims that will not be exercised by the proof script
/ll:explore-api "Claude API tool use" --assume "tools is a list" --assume "stop_reason is tool_use"

# Multi-word target (joined as one string)
/ll:explore-api "Python pathlib"
```

## Acceptance Signals

After running, the following should be true:

- `.ll/learning-tests/<slug>.md` exists and parses as YAML frontmatter
- At least one assertion is `pass` or `fail` (not all `untested`)
- `ll-learning-tests check "$TARGET"` returns exit 0 and the JSON record
- `raw_output_path` points to an existing file with the proof script's captured output

Attribution

BrennonTWilliamsBrennonTWilliams
View sourceSee grades on GitHubMore from BrennonTWilliams →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698621 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →