Agent skill

Fp Pack

by superlucky84 in superlucky84/fp-pack

A skill your agent uses when working in projects that use fp-pack; follow pipe, SideEffect, and curry guidelines.

MITAuto-check passedDevelopment

Install Fp Pack

skills CLI
$ npx skills add superlucky84/fp-pack --skill fp-pack -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install superlucky84/fp-pack fp-pack --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/superlucky84/fp-pack.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/fp-pack .claude/skills/fp-pack && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
fp-pack
GitHub stars
112
Token cost
~3.4k tokens
SKILL.md length
1,157 words
Files
8
Skills in repo
1
Repo updated
First seen
Licence
MIT

At a glance

A skill your agent uses when working in projects that use fp-pack; follow pipe, SideEffect, and curry guidelines.

  • Working in projects that use fp-pack
  • SKILL.md covers ⚠️ Activation Condition (Read…, Core Rules (Keep In Memory), Common Mistakes & Fixes (Top… and Troubleshooting Type Errors…, plus 7 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
  • Curry guidelines

What it does

Fp Pack is an agent skill from superlucky84/fp-pack. Use when working in projects that use fp-pack; follow pipe, SideEffect, and curry guidelines.

Its SKILL.md is about 3.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 10 other files (for example `constraints/common-mistakes.md`, `constraints/core-rules.md` and `constraints/troubleshooting.md`).

It sits in Development, covering Type safety. It works with TypeScript. The repository describes itself as: A functional toolkit focused on type-safe pipelines, not FP dogma, for JavaScript and TypeScript. The licence is MIT.

When your agent uses it

  • Working in projects that use fp-pack
  • Curry guidelines

Example prompts

  • “/fp-pack”

Requirements

  • A credential in STORAGE_KEY

What it can do on your machine

Read from SKILL.md and the folder at commit b9a92e0. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Fp Pack loads about 3.4k tokens when it runs. Until then it costs about 25 tokens; SKILL.md has 1,157 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~25
When it runs · the whole SKILL.md, loaded when a task matches
~3.4k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from superlucky84/fp-pack at commit b9a92e0, republished under its MIT licence (© superlucky84). 1,157 words, ~3,374 tokens.

Download SKILL.mdSave it as .claude/skills/fp-pack/SKILL.md (or your agent's skills folder). This skill also uses 7 other files; get the full folder from GitHub.
name
fp-pack
description
Use when working in projects that use fp-pack; follow pipe, SideEffect, and curry guidelines.
metadata.short-description
fp-pack workflow

fp-pack AI Agent Skills

Document Version: {{version}}

Additional materials (optional):

  • constraints/ (rules, mistakes, troubleshooting)
  • reference/ (composition, currying, TypeScript inference)
  • examples/ (quick examples)

⚠️ Activation Condition (Read First)

These guidelines apply only when fp-pack is installed in the current project.

Before following this document:

  • Check package.json for fp-pack in dependencies/devDependencies
  • Check node_modules/fp-pack exists
  • Check existing code imports from fp-pack or fp-pack/stream

If fp-pack is not installed, use the project's existing conventions. Do not suggest adding fp-pack unless the user asks.


Core Rules (Keep In Memory)

  • Use pipe/pipeAsync for 2+ steps; for a single step, call the function directly.
  • Every pipe checks each step; do not use the deprecated *Strict variants (pipeStrict, pipeAsyncStrict, pipeSideEffectStrict, pipeAsyncSideEffectStrict).
  • Prefer value-first: pipe(value, ...) / pipeAsync(value, ...) runs immediately and improves inference (the input anchors types). Use functions-first only when you need a reusable pipeline.
  • Let pipe infer intermediate parameters; do not add assertions to silence a broken chain. Contextual inference covers 32 steps after the first argument. Compose smaller pipelines beyond that limit; longer already typed chains remain checked.
  • pipeWithDeps infers intermediate values and intersects dependency contracts. Default and deprecated variants have identical checks. Annotate the dependency contract where needed, not every value parameter.
  • If the first arg is a function, it's treated as composition; wrap function values with from().
  • Keep pipeline functions unary; prefer data-last, curried helpers.
  • map/filter are for arrays/iterables, not single values.
  • Use from() only for constants or 0-arg pipelines (including function values you need to pass as data). Otherwise pass data as the first argument.
  • Use pipeSideEffect* only when you need early exit; otherwise use pipe/pipeAsync.
  • Never call runPipeResult/matchSideEffect inside pipelines; call at boundaries.
  • Prefer isSideEffect for precise narrowing; runPipeResult for unwrapping (pipe results are precise; use generics only for values you widened yourself).
  • SideEffect is an instance type: use SideEffect<E> (not typeof SideEffect).
  • If TS inference stalls in data-last generics, use pipeHint or a tiny wrapper.
  • Use fp-pack/stream for large/lazy iterables; array/object utils for small/eager data.
  • Keep DOM/imperative work at the edge; use fp-pack for data transforms.
  • Avoid mutation; return new objects/arrays.
  • When unsure, check dist/index.d.ts or dist/stream/index.d.ts.

Note: For trivial one-liners, using native JS directly is fine. Reach for fp-pack when composition adds clarity or reuse. Keep pipelines short and readable.


Common Mistakes & Fixes (Top Issues)

Don't wrap data in zero-arg functions
ts
// ❌ BAD
pipe(() => [1, 2, 3], filter((n: number) => n % 2 === 0));

// ✅ GOOD (value-first)
pipe([1, 2, 3], filter((n: number) => n % 2 === 0));

// ✅ GOOD (no-input pipeline)
pipe(from([1, 2, 3]), filter((n: number) => n % 2 === 0))();
ifElse/cond need total branches
ts
const status = ifElse((n: number) => n > 0, from('ok'), from('fail'));

const label = cond<number, string>([
  [(n) => n > 0, () => 'positive'],
  [() => true, () => 'non-positive'] // default keeps it total
]);
map is for arrays/iterables (not single values)
ts
const save = pipe(
  (s: AppState) => JSON.stringify({ todos: s.todos, nextId: s.nextId }),
  tap((json) => localStorage.setItem(STORAGE_KEY, json))
);
save(state);
SideEffect pipelines + runPipeResult belong at the boundary
ts
const pipeline = pipeSideEffect(findUser, (user) => user.email);
const result = runPipeResult(pipeline(input)); // outside the pipeline

DOM APIs are imperative by nature—keep them outside or at the boundary (use tap for final effects).


Troubleshooting Type Errors (Fast Checks)

  • Is every step unary? (Pipelines expect one input each.)
  • Are you using array/iterable helpers (map, filter, reduce) on non-arrays?
  • Did you forget a default case in cond ([() => true, () => ...])?
  • Are you returning SideEffect from a pipe pipeline? (Use pipeSideEffect*.)
  • Are you calling runPipeResult inside a pipeline? (Move it to the boundary.)
  • Are you mixing async steps in pipe instead of pipeAsync?
  • Did a data-last generic fail to infer? (Use pipeHint or a tiny wrapper.)
  • Are you using from() for constants only, not normal input?
  • Is a DOM/imperative step inside the pipeline? (Move it to the edge or use tap.)
  • Check dist/index.d.ts / dist/stream/index.d.ts for the expected signature.

If the error persists, reduce the pipeline to the smallest failing step and add types there first.


Quick Examples (3)

Example 1: User Data Processing Pipeline
ts
import { pipe, filter, map, take, sortBy } from 'fp-pack';

const result = pipe(
  users,
  filter((user: User) => user.active),
  sortBy((user) => -user.activityScore),
  map((user) => user.name),
  take(10)
);
Example 2: API Request with Early Exit
ts
import { pipeAsyncSideEffect, SideEffect, runPipeResult } from 'fp-pack';

const result = runPipeResult(
  await pipeAsyncSideEffect(
    'user-123',
    async (userId: string) => {
      const res = await fetch(`/api/users/${userId}`);
      return res.ok ? res : SideEffect.of(() => `HTTP ${res.status}`);
    },
    async (res) => res.json()
  )
);
Example 3: Value-first pipeline
ts
import { pipe, filter, map } from 'fp-pack';

const result = pipe(
  [1, 2, 3, 4, 5],
  filter((n: number) => n % 2 === 0),
  map((n) => n * 2)
);

Core Composition

pipe (sync)
ts
import { pipe, filter, map, take } from 'fp-pack';

const result = pipe(
  users,
  filter((u: User) => u.active),
  map((u) => u.name),
  take(10)
);
pipeAsync (async)
ts
import { pipeAsync } from 'fp-pack';

const user = await pipeAsync(
  userId,
  async (id: string) => fetch(`/api/users/${id}`),
  async (res) => res.json(),
  (data) => data.user
);

Currying & Data-Last

Most multi-arg helpers are data-last and curried. Pair them with value-first pipe(value, ...) to anchor types:

  • Good: map(fn), filter(pred), replace(from, to), assoc('k', v), path(['a','b'])
  • Single-arg helpers are already unary—just use them directly

TypeScript: Data-last Generic Inference

Some data-last helpers return a generic function whose type is only determined by the final data argument. Prefer value-first pipe(value, ...) so the input anchors generics; use hints when needed.

Quick fix (pipeHint or wrapper)
ts
import { pipe, pipeHint, zip, some } from 'fp-pack';

// Prefer value-first to anchor generics
const values: number[] = [1, 2, 3];
const withValueFirst = pipe(
  values,
  zip([1, 2, 3]),
  some(([a, b]) => a > b)
);

const withPipeHint = pipe(
  pipeHint<number[], Array<[number, number]>>(zip([1, 2, 3])),
  some(([a, b]) => a > b)
);

If you prefer, a tiny wrapper like (values) => zip([1, 2, 3], values) works too.

Utilities that may need a hint in data-last pipelines:

  • Array: chunk, drop, take, zip
  • Object: assoc, assocPath, dissocPath, evolve, mapValues, merge, mergeDeep, omit, path, pick, prop
  • Async: timeout
  • Stream: chunk, drop, take, zip

Show full SKILL.md (473 more words)Show less

SideEffect Pattern (Use Only When Needed)

Most code should use pipe / pipeAsync. Use SideEffect-aware pipes only when you need early termination:

  • validation pipelines that should stop early
  • recoverable errors you want to model as data
  • branching flows where you want to short-circuit
SideEffect-aware pipes
  • pipeSideEffect / pipeAsyncSideEffect: stop at the first SideEffect; the result carries the precise effect union (plain T when no step can return a SideEffect)
  • pipeSideEffectStrict / pipeAsyncSideEffectStrict: deprecated aliases — do not use
Key functions
  • SideEffect.of(effectFn, label?)
  • isSideEffect(value) (type guard)
  • runPipeResult(result) (execute effect or return value; outside pipelines)
Example
ts
import { pipeSideEffect, SideEffect, isSideEffect, runPipeResult } from 'fp-pack';

const validate = (n: number) => (n > 0 ? n : SideEffect.of(() => 'NEG' as const));
const result = pipeSideEffect(
  -1,
  validate,
  (n) => n + 1
); // number | SideEffect<'NEG'>

if (isSideEffect(result)) {
  const err = runPipeResult(result); // 'NEG'
} else {
  // result is number
}
Type Safety Notes
  • pipeSideEffect/pipeAsyncSideEffect preserve precise effect unions.
  • runPipeResult returns T | E for a pipe result and E after narrowing to SideEffect<E>; it becomes any only if you widen the input yourself to SideEffect<any>/any.
  • Prefer isSideEffect for precise branch narrowing.

Stream Functions (fp-pack/stream)

Use stream utilities when:

  • data is large or unbounded
  • you want lazy evaluation
  • you want to support Iterable and AsyncIterable

If any input is async, the output is async. Use toAsync to normalize inputs when needed.

ts
import { pipe } from 'fp-pack';
import { range, filter, map, take, toArray } from 'fp-pack/stream';

const result = pipe(
  range(Infinity),
  filter((n: number) => n % 2 === 0),
  map((n) => n * n),
  take(100),
  toArray
);

Available Functions (Quick Index)

Composition
  • pipe, pipeAsync
  • SideEffect-aware: pipeSideEffect, pipeAsyncSideEffect
  • Deprecated aliases (do not use): pipeStrict, pipeAsyncStrict, pipeSideEffectStrict, pipeAsyncSideEffectStrict
  • Utilities: from, tap, tap0, once, memoize, identity, constant, curry, compose
  • SideEffect helpers: SideEffect, isSideEffect, matchSideEffect, runPipeResult
Array
  • Transforms: map, filter, flatMap, reduce, scan
  • Queries: find, some, every
  • Slicing: take, drop, chunk
  • Ordering: sort, sortBy, groupBy, uniqBy
  • Combining: zip, concat, append, flatten
Object
  • Access: prop, path, propOr, pathOr
  • Pick/drop: pick, omit
  • Updates: assoc, assocPath, dissocPath
  • Merge: merge, mergeDeep
  • Transforms: mapValues, evolve
Control Flow
  • ifElse, when, unless, cond, guard, tryCatch
Async
  • retry, timeout, delay
  • debounce*, throttle
Stream (Lazy Iterables)
  • Building: range
  • Transforms: map, filter, flatMap, flatten
  • Slicing: take, drop, chunk
  • Queries: find, some, every, reduce
  • Combining: zip, concat
  • Utilities: toArray, toAsync
Others
  • Math: add, sub, mul, div, clamp
  • String: split, join, replace, trim
  • Equality: equals, isNil
  • Debug: assert, invariant

Micro-Patterns (Optional)

Boundary handling
ts
const pipeline = pipeSideEffect(validate, process);

export const handler = (data) => {
  const result = pipeline(data);
  if (isSideEffect(result)) return runPipeResult(result);
  return result;
};
Value-first execution
ts
const result = pipe(
  [1, 2, 3, 4, 5],
  filter((n: number) => n % 2 === 0),
  map((n) => n * 10)
); // [20, 40]
from() for constants / 0-arg pipelines
ts
const result = pipe(
  from([1, 2, 3, 4, 5]),
  filter((n: number) => n % 2 === 0),
  map((n) => n * 10)
)(); // [20, 40]
Stream to array
ts
const toIds = pipe(
  filter((u: User) => u.active),
  map((u) => u.id),
  toArray
);
Object updates
ts
const updateAccount = pipe(
  assocPath(['profile', 'role'], 'member'),
  merge({ updatedAt: Date.now() })
);

Decision Guide

  • Is everything sync and pure? → pipe
  • Any step async? → pipeAsync
  • Need early-exit? → pipeSideEffect / pipeAsyncSideEffect (effect unions are precise)
  • Only one step? → call the function directly (no pipe)
  • Handling result at boundary? → isSideEffect for branching, runPipeResult to unwrap
  • Large/unbounded/iterable data? → fp-pack/stream

Import Paths

  • Main: import { pipe, map, filter } from 'fp-pack'
  • SideEffect: import { pipeSideEffect, SideEffect } from 'fp-pack'
  • Async: import { pipeAsync, retry, timeout } from 'fp-pack'
  • Stream: import { map, filter, toArray } from 'fp-pack/stream'

Quick Signature Lookup (When Unsure)

If TypeScript inference is stuck or you need to verify a function signature:

In fp-pack project:

  • Main types: dist/index.d.ts
  • Stream types: dist/stream/index.d.ts

In consumer project:

  • Main types: node_modules/fp-pack/dist/index.d.ts
  • Stream types: node_modules/fp-pack/dist/stream/index.d.ts

Summary

Default to value-first pipe / pipeAsync for inference, keep helpers data-last and unary, switch to stream/* when laziness matters, and reserve SideEffect-aware pipelines for true early-exit flows. Use functions-first only for reusable pipelines. Use isSideEffect for precise narrowing and call runPipeResult only at the boundary.

© superlucky84, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 7 other files in skills/fp-pack of superlucky84/fp-pack.

  • SKILL.md
  • constraints/common-mistakes.md
  • constraints/core-rules.md
  • constraints/troubleshooting.md
  • examples/quick-examples.md
  • reference/composition.md
  • reference/currying-data-last.md
  • reference/typescript-inference.md

Open the folder on GitHubat commit b9a92e0

Compare with similar skills

Fp Pack next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Fp Pack compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Fp Pack this skillsuperlucky84/fp-pack112—~3.4kAutomated safety check: PassMIT
Typescript Advanced Typesrolling-scopes/rsschool-app10k25 repos~4.2kAutomated safety check: PassMPL-2.0
Wagmi Feature Developmentwevm/wagmi6.8k—~3.8kAutomated safety check: PassMIT
Convert Internal Package to TypeScriptTryGhost/Ghost55k—~1.2kAutomated safety check: PassMIT
Add NodeBridge Handlerneovateai/neovate-code1.6k—~1kAutomated safety check: PassMIT
AST Visitor Pattern for Unionsprisma/orm48k—~830Automated safety check: PassApache-2.0

Similar skills

  • Typescript Advanced Types

    rolling-scopes/rsschool-app

    Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications.

    10k GitHub starsUsed in 25 repos~4.2k tokens
    DevelopmentAuto-check passed
  • Walks through adding a Wagmi feature across its layers: a Viem-based core action, TanStack Query options, and React and Vue bindings.

    6.8k GitHub stars~3.8k tokensUpdated 7 days ago
    DevelopmentAuto-check passed
  • Moves a legacy internal Ghost package from JavaScript and CommonJS to TypeScript and ESM in three focused commits that keep git file history intact.

    55k GitHub stars~1.2k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Add NodeBridge Handler

    neovateai/neovate-code

    Walks through adding a message handler to NodeBridge in Neovate Code, from the implementation and its types to an optional test entry and a run with Bun.

    1.6k GitHub stars~1k tokensUpdated 6 mo ago
    DevelopmentAuto-check passed
  • Official

    Replaces a plain TypeScript union plus switch statements with frozen subclasses and a visitor interface when several places dispatch on the same variants.

    48k GitHub stars~830 tokensUpdated today
    DevelopmentAuto-check passed
  • Bumpy Add Change

    zap-studio/monorepo

    Create a bumpy bump file describing which packages changed and how, for version bumping and changelog generation.

    172 GitHub starsUsed in 1 repo~1.4k tokens
    DevelopmentAuto-check: notes

Works with

Categories

Questions about Fp Pack

What does Fp Pack do?

A skill your agent uses when working in projects that use fp-pack; follow pipe, SideEffect, and curry guidelines. Fp Pack is an agent skill from superlucky84/fp-pack. Use when working in projects that use fp-pack; follow pipe, SideEffect, and curry guidelines.

When should I use Fp Pack?

Fp Pack fits situations like: working in projects that use fp-pack; curry guidelines.

How do I install Fp Pack in Claude Code?

Run `npx skills add superlucky84/fp-pack --skill fp-pack -a claude-code`. Or copy the skill folder (skills/fp-pack in superlucky84/fp-pack) into .claude/skills/fp-pack in your project. Claude Code loads it when a task matches its description.

How do I install Fp Pack in Codex?

Run `npx skills add superlucky84/fp-pack --skill fp-pack -a codex`. Or copy the skill folder (skills/fp-pack in superlucky84/fp-pack) into .agents/skills/fp-pack in your project. Codex loads it when a task matches its description.

Can I use Fp Pack in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add superlucky84/fp-pack --skill fp-pack -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/fp-pack, .gemini/skills/fp-pack, .github/skills/fp-pack and .opencode/skills/fp-pack in your project.

What does Fp Pack need to run?

SKILL.md names no scripts, command-line tools or credentials: Fp Pack is instructions for the agent only. Our summary lists: A credential in STORAGE_KEY.

Does Fp Pack access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Fp Pack safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Fp Pack use?

Fp Pack is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Fp Pack use?

About 3.4k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Fp Pack?

Skills that share tags, products or a category with Fp Pack: Typescript Advanced Types (rolling-scopes/rsschool-app, 10k stars), Wagmi Feature Development (wevm/wagmi, 6.8k stars), Convert Internal Package to TypeScript (TryGhost/Ghost, 55k stars) and Add NodeBridge Handler (neovateai/neovate-code, 1.6k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Fp Pack?

superlucky84 (a GitHub user) maintains it in superlucky84/fp-pack, which has 112 GitHub stars. The repository was last updated on October 2, 2026.

Source: superlucky84/fp-pack on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.