functional-core-imperative-shell
Use when writing or refactoring code, before creating files - enforces separation of pure business logic (Functional Core) from side effects (Imperative Shell) using FCIS pattern with mandatory file classification
What this skill does
# Functional Core, Imperative Shell (FCIS)
## Overview
**Core principle:** Separate pure business logic (Functional Core) from side effects (Imperative Shell). Pure functions go in one file, I/O operations in another.
**Why this matters:** Pure functions are trivial to test (no mocks needed). I/O code is isolated to thin shells. Bugs become structurally impossible when business logic has no side effects.
## When to Use
**Use FCIS when:**
- Writing any new code file
- Refactoring existing code
- Reviewing code for architectural decisions
- Deciding where logic belongs
**Trigger symptoms:**
- "Where should this function go?"
- Creating a new file
- Adding database calls to logic
- Adding file I/O to calculations
- Writing tests that need complex mocking
## File Type Definitions
### Functional Core Files
**Contains ONLY:**
- Pure functions (same input -> same output, always)
- Business logic, validations, calculations, transformations
- Data structure operations
- Logging (EXCEPTION: loggers are permitted in Functional Core)
**NEVER contains:**
- File I/O (reading, writing files)
- Database operations (queries, updates, connections)
- HTTP requests or responses
- Environment variable access
- Date.now(), Math.random(), or other non-deterministic functions
- State mutations outside function scope
**Logging exception:** Functions MAY accept and use loggers. For unit tests, pass no-op loggers. This is the ONLY permitted side effect in Functional Core.
**Test signature:** Simple assertions, no mocks except logger (if used).
### Imperative Shell Files
**Contains ONLY:**
- I/O operations: file system, database, HTTP, environment
- Orchestration: gather data -> call Functional Core -> persist results
- Error handling for I/O failures
- Minimal business logic (coordination only)
**NEVER contains:**
- Complex calculations
- Business rule validations
- Data transformations beyond format conversion
**Test signature:** Integration tests with real dependencies or test doubles.
## Code Flow Pattern
```
1. GATHER (Shell): Collect data from external sources
2. PROCESS (Core): Transform input to output (pure)
3. PERSIST (Shell): Save results externally
```
**Every operation follows this sequence.** No exceptions.
## Decision Framework
Before writing a function, ask:
```dot
digraph fcis_decision {
"Writing a function" [shape=ellipse];
"Can run without external dependencies?" [shape=diamond];
"Does it coordinate I/O?" [shape=diamond];
"Functional Core" [shape=box, style=filled, fillcolor=lightblue];
"Imperative Shell" [shape=box, style=filled, fillcolor=lightgreen];
"STOP: Refactor or escalate" [shape=octagon, style=filled, fillcolor=red, fontcolor=white];
"Writing a function" -> "Can run without external dependencies?";
"Can run without external dependencies?" -> "Functional Core" [label="yes"];
"Can run without external dependencies?" -> "Does it coordinate I/O?" [label="no"];
"Does it coordinate I/O?" -> "Imperative Shell" [label="yes"];
"Does it coordinate I/O?" -> "STOP: Refactor or escalate" [label="no"];
}
```
**Questions to ask:**
- Can this logic run without file system, database, network, or environment?
- **YES** -> Functional Core
- **NO** -> Does it coordinate I/O or contain business logic?
- **I/O coordination** -> Imperative Shell
- **Business logic + I/O** -> STOP. Refactor or escalate to user.
## Common Mistakes and Rationalizations
| Excuse/Thought Pattern | Reality | What To Do |
| --------------------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------ |
| "Just one file read in this calculation" | File I/O = side effect. Not Functional Core. | Extract to Shell. Pass data as parameter. |
| "Database is passed as parameter, so it's pure" | Database operations are I/O. Not pure. | Move to Shell. Core receives data, not DB connection. |
| "This validation needs to check if file exists" | File system check = I/O. Not Functional Core. | Shell checks file, passes boolean to Core validation. |
| "Small HTTP call, won't hurt" | HTTP = side effect. Breaks purity guarantee. | Shell makes request, Core processes response data. |
| "Need Date.now() for timestamp calculation" | Non-deterministic. Not pure. | Shell passes timestamp as parameter. |
| "Logging is a side effect, should remove" | **WRONG.** Logging is explicitly permitted. | Keep logger. This is the exception. |
| "This function does both logic and I/O, but it's simpler" | Mixed concerns = untestable without mocks. | Split into Core (logic) + Shell (I/O). Test Core simply. |
| "I'll refactor later" | Later never comes. Do it now. | Classify and separate now. |
| "Performance requires mixing" | Prove it with benchmarks. Usually wrong. | Separate first. Optimize with evidence. Mark Mixed (unavoidable) with justification. |
## Red Flags - STOP and Refactor
If you catch yourself doing ANY of these, STOP:
- **File I/O in a "pure" function** (open, read, write, exists checks)
- **Database passed as parameter to Functional Core** (queries, updates, connections)
- **HTTP requests in business logic** (fetch, axios, requests)
- **Environment variables in calculations** (process.env, os.getenv)
- **Math.random() or Date.now() in Functional Core** (non-deterministic)
- **Thinking "just this once" about mixing concerns**
**All of these mean:** Extract I/O to Shell. Pass data to Core. Classify file correctly.
## Implementation Patterns
### Functional Core Pattern
```python
# pattern: Functional Core
def calculate_total_with_tax(items, tax_rate, logger=None):
"""Pure calculation: same inputs always produce same output."""
if logger:
logger.debug(f"Calculating total for {len(items)} items")
subtotal = sum(item['price'] * item['quantity'] for item in items)
tax = subtotal * tax_rate
total = subtotal + tax
return {
'subtotal': subtotal,
'tax': tax,
'total': total
}
```
**No I/O. No database. No file system. Only computation.**
### Imperative Shell Pattern
```python
# pattern: Imperative Shell
def process_order(order_id, db, logger):
"""Orchestrates: gather -> process -> persist."""
# GATHER: Collect data from external sources
items = db.get_order_items(order_id)
tax_rate = db.get_tax_rate_for_order(order_id)
# PROCESS: Call Functional Core (pure logic)
result = calculate_total_with_tax(items, tax_rate, logger)
# PERSIST: Save results externally
db.update_order_total(order_id, result['total'])
return result
```
**Shell is thin. Core does heavy lifting. Testable separately.**
### Mixed (Needs Refactoring) - Bad Example
```python
# pattern: Mixed (needs refactoring)
def calculate_and_save_total(order_id, db):
"""BAD: Mixes calculation with I/O. Hard to test."""
items = db.get_order_items(order_id) # I/O
subtotal = sum(item['price'] for item in items) # Logic
tax_rate = db.get_tax_rate_for_order(order_id) # I/O
tax = subtotal * tax_rate # Logic
total = subtotal + tax # Logic
db.update_order_total(order_id, total) # I/O
return total
```
**Testing this requires database mocks. Fragile. Refactor uRelated in Writing & Docs
jax-development
IncludedUse this skill when the user is writing, debugging, profiling, refactoring, reviewing, benchmarking, parallelising, exporting, or explaining JAX code, or when they mention JAX, jax.numpy, jit, grad, value_and_grad, vmap, scan, lax, random keys, pytrees, jax.Array, sharding, Mesh, PartitionSpec, NamedSharding, pmap, shard_map, Pallas, XLA, StableHLO, checkify, profiler, or the JAX repo. It helps turn NumPy or PyTorch-style code into pure functional JAX, fix tracer/control-flow/shape/PRNG bugs, remove recompiles and host-device syncs, choose transforms and sharding strategies, inspect jaxpr/lowering/IR, and benchmark compiled code correctly.
nature-article-writer
IncludedDrafts, rewrites, diagnostically critiques, and style-calibrates primary research manuscripts for Nature and Nature Portfolio journals. Use when the user wants a Nature-style title, summary paragraph or abstract, introduction, results, discussion, methods, figure legends, presubmission enquiry, cover letter, reviewer response, or when a scientific draft sounds generic, jargon-heavy, structurally weak, or AI-ish and needs precise, broad-reader-friendly prose without inventing data, analyses, or references. Best for primary research articles and letters rather than reviews or press releases unless explicitly adapting one.
deckrd
IncludedDocument-driven framework that derives requirements, specifications, implementation plans, and executable tasks from goals through structured AI dialogue. Use when user says "write requirements", "create spec", "plan implementation", "derive tasks", "structure this feature", "break down into tasks", or "document this module". Also use for reverse engineering existing code into docs (/deckrd rev). Do NOT use for direct code writing — use /deckrd-coder after tasks are generated. Do NOT use when the user only wants to run or fix existing code without planning.
clinical-decision-support
IncludedGenerate professional clinical decision support (CDS) documents for pharmaceutical and clinical research settings, including patient cohort analyses (biomarker-stratified with outcomes) and treatment recommendation reports (evidence-based guidelines with decision algorithms). Supports GRADE evidence grading, statistical analysis (hazard ratios, survival curves, waterfall plots), biomarker integration, and regulatory compliance. Outputs publication-ready LaTeX/PDF format optimized for drug development, clinical research, and evidence synthesis.
handling-sf-data
IncludedSalesforce data operations with 130-point scoring. Use this skill to create, update, delete, bulk import/export, generate test data, and clean up org records using sf CLI and anonymous Apex. TRIGGER when: user creates test data, performs bulk import/export, uses sf data CLI commands, needs data factory patterns for Apex tests, or needs to seed/clean records in a Salesforce org. DO NOT TRIGGER when: SOQL query writing only (use querying-soql), Apex test execution (use running-apex-tests), or metadata deployment (use deploying-metadata).
accelint-ac-to-playwright
IncludedConvert and validate acceptance criteria for Playwright test automation. Use when user asks to (1) review/evaluate/check if AC are ready for automation, (2) assess if AC can be converted as-is, (3) validate AC quality for Playwright, (4) turn AC into tests, (5) generate tests from acceptance criteria, (6) convert .md bullets or .feature Gherkin files to Playwright specs, (7) create test automation from requirements. Handles both bullet-style markdown and Gherkin syntax with JSON test plan generation and validation.