Skip to content
Back to skills

Ops Crate

ASecurity

Generate a new ops/xxx crate for an external service integration. Identifies the right pattern (A=wrapper, B=HTTP direct, C=macro), scaffolds the full structure, and runs the quality checklist. Trigger on "ops crate", "new ops", "creer un crate ops", "add ops/xxx", "nouveau crate ops", "ironflow ops".

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 6, 2026
developmentrustgobashgitapidocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned October 6, 2026

npx -y skills add ThomasTartrau/ironflow --skill ops-crate --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ops Crate?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ops Crate
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/thomastartrau-ops-crate/badge)](https://www.skillsdirectory.com/skills/thomastartrau-ops-crate)

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

Download with Pro
SKILL.md
---
name: ops-crate
description: Generate a new ops/xxx crate for an external service integration. Identifies the right pattern (A=wrapper, B=HTTP direct, C=macro), scaffolds the full structure, and runs the quality checklist. Trigger on "ops crate", "new ops", "creer un crate ops", "add ops/xxx", "nouveau crate ops", "ironflow ops".
argument-hint: "<service-name> [pattern-a|pattern-b|pattern-c]"
---

# ops-crate -- Generate a new Ironflow ops crate

## Arguments

`$ARGUMENTS` -- expected: `<service-name>` and optionally a pattern override.

Parse the arguments:
- First word: the service name (e.g. `datadog`, `pagerduty`, `cloudflare`)
- Second word (optional): `pattern-a`, `pattern-b`, or `pattern-c`

If no service name is given, ask for one.

## Step 1: Check if the crate already exists

```bash
test -d "ops/$SERVICE" && echo "EXISTS" || echo "NEW"
```

If EXISTS: warn the user and ask whether to continue (extend) or abort.

## Step 2: Identify the pattern

Read the reference files to understand each pattern:
- `references/pattern-a-wrapper.md` -- Pattern A
- `references/pattern-b-http.md` -- Pattern B
- `references/pattern-c-macro.md` -- Pattern C
- `references/common-helpers.md` -- Shared helpers

### If a pattern was specified in arguments

Use it directly.

### If no pattern was specified

Ask the user with AskUserQuestion:

| Criterion | Pattern A (Wrapper) | Pattern B (HTTP direct) | Pattern C (Macro) |
|-----------|---------------------|-------------------------|-------------------|
| Rust crate exists on crates.io? | Yes, with uniform trait | No | Yes, with typed methods 1:1 |
| HTTP handled by | Underlying crate | ironflow-ops-common's HttpApiClient | Underlying crate |
| Operation granularity | Generic `Op<E>` for all endpoints | One struct per endpoint | Macro-generated per method |
| Boilerplate | Minimal | Medium (one struct per operation) | Minimal (macro generates) |
| Reference crates | ops/gitlab, ops/k8s | ops/grafana, ops/loki, ops/tempo, ops/mimir | ops/slack |

Recommend Pattern B if unsure -- it is the most common and self-contained.

## Step 3: Scaffold the crate

Follow the structure from the chosen pattern's reference file.

### 3a. Create directory

```bash
mkdir -p ops/$SERVICE/src
```

### 3b. Create Cargo.toml

Use `cargo add` after creating the basic file. The template is in
`references/common-helpers.md` (Pattern B) or adapt for A/C.

**Pattern B dependencies:**
- `ironflow-core` (path = "../../ironflow-core")
- `ironflow-ops-common` (path = "../common")
- `async-trait`
- `reqwest` with features ["json", "query"]
- `serde` with features ["derive"]
- `serde_json`
- Dev: `tokio` with features ["full"], `wiremock`

**Pattern A dependencies:**
- `ironflow-core` (path = "../../ironflow-core")
- `async-trait`
- The underlying Rust crate
- `serde_json`
- Dev: `tokio` with features ["full"]

**Pattern C dependencies:**
- `ironflow-core` (path = "../../ironflow-core")
- `async-trait`
- The underlying Rust crate
- `serde`, `serde_json`
- Dev: `tokio` with features ["full"]

### 3c. Create source files

Follow the exact structure from the reference file for the chosen pattern.

**Pattern B files:**
1. `src/lib.rs` -- crate-level doc, pub modules, `pub use client::XxxClient`
2. `src/client.rs` -- XxxClient wrapping HttpApiClient (copy structure from reference)
3. One example module with 1-2 operations to demonstrate the pattern
4. `tests/` directory with wiremock integration tests

**Pattern A files:**
1. `src/lib.rs` -- crate-level doc, re-exports, `pub use underlying_crate`
2. `src/client.rs` -- XxxClient with from_context + op()
3. `src/operation.rs` -- XxxOp<E> generic Operation wrapper

**Pattern C files:**
1. `src/lib.rs` -- crate-level doc, re-exports
2. `src/client.rs` -- XxxClient with from_context, session()
3. `src/error.rs` -- error conversion
4. `src/macros.rs` -- xxx_op! macro
5. One example module using the macro

### 3d. Register in workspace

Add `"ops/$SERVICE"` to the `members` list in the root `Cargo.toml`.

## Step 4: Quality checklist

Run these commands and fix any issues:

```bash
cargo clippy --all-targets -p ironflow-ops-$SERVICE
cargo doc --no-deps -p ironflow-ops-$SERVICE
cargo test -p ironflow-ops-$SERVICE
```

### Verify no duplication with ops/common

Check that the new crate does NOT re-implement any of these helpers:
- `check_response` / `check_response_json`
- `validate_path_segment`
- `send_request`
- `parse_json_body`
- `to_value` (Pattern B must use `ironflow_ops_common::helpers::to_value`)
- `reqwest_err`

Exception: Pattern C's `macros.rs` has its own `to_value` with a
service-specific error origin -- this is intentional.

### Mandatory tests (all patterns)

Every ops crate MUST include at minimum:

**Client tests:**
- `from_context_fails_when_token_missing` -- fast, no network
- `new` trims trailing slash on base URL (Pattern B only)
- `new` rejects empty token
- `debug_does_not_leak_token` -- format with Debug, assert token absent

**Operation tests (Pattern B with wiremock):**
- URL constructed correctly (mock matches on `path`)
- Auth header sent (mock matches on `bearer_token`)
- Body sent correctly (POST/PUT/PATCH)
- 4xx/5xx returns OperationError::Http
- `input()` does NOT contain secrets
- `kind()` returns the correct service name

**Operation tests (Pattern A -- mostly #[ignore]):**
- `kind()` returns the correct service name
- `input()` returns endpoint metadata

**Operation tests (Pattern C):**
- `to_value` serializes a struct
- `to_value` serializes unit to null

### Documentation requirements

Every public item needs rustdoc:
- `//!` for crate-level and module-level docs
- `///` for structs, enums, traits, functions, methods
- `# Examples` with `no_run` for anything needing network
- `# Errors` for every `Result`-returning function

## Step 5: Suggest next steps

After generation, tell the user:

1. Add the actual operations for the target API
2. Run the full test suite: `cargo test -p ironflow-ops-$SERVICE`
3. Consider adding the crate to the `ironflow-ops` meta-crate if one exists

## Conventions

- All code follows the project's CLAUDE.md rules (imports at top, no inline paths)
- Use `?` operator for error propagation, return `OperationError` variants
- `Debug` implementations MUST redact secrets
- `input()` implementations MUST NOT include secrets
- Crate names follow the pattern `ironflow-ops-$SERVICE`
- Package names use hyphens: `ironflow-ops-xxx`
- Module names use underscores in Rust: `ironflow_ops_xxx`

Files in this skill

  • SKILL.md6.4 KB
  • references/common-helpers.md3.6 KB
  • references/pattern-a-wrapper.md4.4 KB
  • references/pattern-b-http.md9.5 KB
  • references/pattern-c-macro.md6.8 KB

Attribution

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

Loading comments…