Haskell Development (Entry Point)
Orientation skill for any Haskell work. The opinionated stack and conventions are partitioned across focused sub-skills; this is the map that tells you which to load when. Don't try to recall sub-skill content from this map — invoke them on demand via the Skill tool.
Sub-skill map
| Sub-skill | Invoke when working on |
|---|---|
haskell-devcontainer |
Detecting or setting up the pre-built devcontainer (ivelten/haskell-devcontainer), .devcontainer/ files, VS Code extensions, direnv inside the container |
haskell-toolchain-mise |
Provisioning the toolchain natively on the host: mise.toml pins, GHC/HLS via GHCup, HLS↔GHC compatibility, PATH and shims, .envrc with use mise |
haskell-project-setup |
Bootstrapping a repo: .cabal/cabal.project, project layout, language extensions, Hoogle, fast-tags, direnv |
haskell-type-design |
Modeling domain types, newtypes, sum types, "parse don't validate", phantom types, records, field naming |
haskell-domain-errors |
Designing error ADTs, Show/ToJSON/Exception instances, choosing Either vs Error effect vs throwIO |
haskell-effectful |
Application architecture, defining effects, writing interpreters (production + in-memory), composition in main |
haskell-database |
PostgreSQL modeling with Rel8, type-mapping decisions (composite vs jsonb vs enum), HKD table definitions, queries, migrations |
haskell-json |
Aeson ToJSON/FromJSON: TaggedObject discriminator for sum types, fieldLabelModifier, manual instances for non-record constructors |
haskell-logging |
Adding log-effectful, choosing severities, structured payloads, localData scoping |
haskell-testing |
hspec setup, QuickCheck properties, hspec-discover, colored output, testing effectful code |
haskell-documentation |
Haddock conventions, doctest setup, the Haddock coverage gate, fixing broken Haddock references |
haskell-benchmarking |
tasty-bench/weigh, regression detection, GHC profiling, space-leak hunting |
haskell-quality-gates |
ormolu, hlint, cabal-gild, pre-commit hooks, CI config, performance defaults, the "done" checklist |
haskell-debugging |
GHCi debugger (:break, :step, :trace), DAP setup (haskell-dap/ghci-dap/haskell-debug-adapter), VS Code launch.json |
Environment selection (first decision on a fresh project)
Before any build config, the project needs a toolchain. Run both detections first — only ask if neither fires:
grep -q "ivelten/haskell-devcontainer" .devcontainer/docker-compose.yml 2>/dev/null && echo "devcontainer"
ls mise.toml .mise.toml 2>/dev/null && echo "native (mise)"
If neither is configured, ask which the user wants, with the trade-off:
- Native,
mise+ GHCup →haskell-toolchain-mise. No Docker, no VM overhead — the difference is large on macOS, where every container is a Linux VM. Costs a one-time toolchain install per machine. - Devcontainer →
haskell-devcontainer. Zero-setup, disposable, matches a Linux CI, and hosts Docker services (Postgres) next to the app. Costs virtualization overhead on macOS.
Neither is the default. Ask, then load the matching sub-skill; haskell-project-setup handles everything downstream of that choice.
Routing rules
- When a task spans multiple topics, invoke sub-skills in the order they're needed. A fresh project starts with the environment selection above, then
haskell-project-setup, then others as features arrive. - Don't preemptively load all sub-skills at session start. The map above is the orientation; load each one on demand when its topic actually surfaces.
- If a sub-skill is already loaded in this session, don't reload it.
- The specific sub-skills' own descriptions may also fire automatically on later messages — let them. This umbrella complements those triggers, it doesn't replace them.
Defaults that hold regardless of which sub-skill is active
If you have to write Haskell before any specific sub-skill has loaded, these are the floor:
- Stack:
cabal+ GHCup-provisioned GHC 9.10.3 (via devcontainer ormisenatively),effectfulfor effects,hspec+QuickCheckfor tests,ormolu+hlintfor hygiene, Haddock + doctest for docs. - Pin GHC from the HLS support list, never the reverse — HLS bindists target specific GHC patch versions (9.10.3 is the only 9.10.x supported by HLS 2.14).
- Do not use
stack, Nix shells,mtl,polysemy, orfused-effectsunless the user explicitly asks. - Total functions, strict fields,
TextnotString, explicit export lists, Haddock on every public binding.
Detail for each of these lives in the relevant sub-skill; load it when you reach for the topic.