Back to Explorer
Beginner Friendly Open-Source Haskell

Good First Issues in Haskell

Explore curated starter issues in high-scoring Haskell repositories. Every listed issue belongs to a welcoming repository scored by C-Rank™ on PR merge rates, review responsiveness, and first-timer acceptance.

Updated: Mon, 31 Aug 2026 UTC (Live GitHub Sync)
Real-Time Radar

Arm Issue Sniper for fresh Haskell beginner issues

Beginner issues in welcoming S/A-Tier repositories get snatched within 15 minutes. Receive instant alerts on Discord, Telegram, or Email the minute a maintainer opens a new task.

Live Good First Issues (30)

Real-Time Open GitHub Issues
well-typed/haskell-debugger146 Tier A · 64 pts
#358Opened 5 days ago
Running hdb non-existent-file.hs fails with a terrible errr

If you hdb app/Main.hs and app/Main.hs doesn't exist, you get an error message about ghc --numeric-version failing. Instead, we should make sure the target exists before trying to set up and fail with an error message gracefully

help wantednewcomer 🌱
GaloisInc/saw-script517 Tier A · 70 pts
#3377Opened 6 days ago
Add `bvEq_refl` to `basic_ss`

In the course of chasing #3343 it became clear that bvEq_refl is missing from basic_ss. This is silly and should be fixed. (There are reasons to not necessarily unfold or rewrite equalities, which is why a lot of the equality-related rules are left out. But those reasons don't extend to reducing reflexivity.)

type: bugeasyusabilitysubsystem: saw-core
flora-pm/flora-server156 Tier S · 73 pts
#1233Opened 17 days ago
Use a more appropriate data structure in `Flora.Domain.Category.Normalise`

We use a naïve List.find when normalising categories, which is linear in complexity. We can probably use a Map instead.

good first issueperformance
1
flora-pm/flora-server156 Tier S · 73 pts
#1232Opened 17 days ago
Remove dependency on `colourista`

We only use blue/red messages when starting the executables, we should vendor those.

good first issue
1
flora-pm/flora-server156 Tier S · 73 pts
#1231Opened 17 days ago
Drop the `iso8601-time` library in favour of `Data.Time.Format.ISO8601`

Today, iso8601-time is only used for parseISO8601, but we already use iso8601ParseM from the time library elsewhere, so no need for an extra dep.

good first issue
1
circuithub/rel8169 Tier B · 50 pts
#408Opened 1 month ago
Add function for checking ranges are currently valid

In the CircuitHub codebase we have: -- | @range \@> now()@: true when the current timestamp falls within the range. currentlyValid :: Expr (Range UTCTime) -> Expr Bool currentlyValid range = rawBinaryOperator "@>" range now we should upstream this or something similar, since this is something we want to quite often do with ranges.

enhancementhelp wantednice to have
GaloisInc/saw-script517 Tier A · 70 pts
#3358Opened 1 month ago
`include_once` needs to normalize paths before checking if they're the same

Suppose you have these files: a/a.saw b/b.saw c/c.saw and suppose both b.saw and c.saw do include_once "../a/a.saw", and c.saw also includes b.saw. Then from the perspective of c.saw the path of a.saw is ../a/a.saw, but from the perspective of b.saw the path is ../b/../a/a.saw, because we try to make includes relative to where they're included from. But include_once just looks at the path strings, and they're different, so this doesn't work as intended. This does, however, seem like a reasonable thing to do and to want include_once to work for, so I guess we do need it to normalize paths for comparison... much as normalizing paths is annoying and generally wrong. (That or we could check the system-level file identity... but I'm not sure how you do that from Haskell or whether it's workable in Windows.) @qsctr

type: bugeasyneeds testusability
6
pschachte/wybe55 Tier A · 68 pts
#581Opened 1 month ago
Fix name mangling

Currently, names produced in generated LLVM code are not consistently mangled to ensure they don't clash with one another or with user-written code. We should think through how much mangling is needed for this, and implement it consistently for all generated names in LLVM code.

good first issuecleanup
neohaskell/NeoHaskell347 Tier A · 66 pts
#729Opened 1 month ago
Missing `ToSchema` instance for `DateTime` — read-model/API records with a timestamp field don't compile

Summary DateTime (core/core/DateTime.hs) derives ToJSON/FromJSON but has no ToSchema instance. Because Schema's generic derivation requires every field's type to have ToSchema, any record exposed through the web transport — a query read model registered via deriveQuery / withQuery, or any type deriving ToSchema — fails to compile the moment it contains a DateTime (or Maybe DateTime) field. Since DateTime is the natural type for timestamps carried on events and folded onto entities, this makes it impossible to surface a timestamp on an HTTP read model without a workaround (an orphan instance, or converting the field to Int epoch seconds / Text first). Reproduction import Core data Row = Row { id :: Uuid , occurredAt :: DateTime -- or `Maybe DateTime` } deriving (Generic) instance ToSchema Row -- ❌ No instance for `ToSchema DateTime` Maybe DateTime fails the same way — instance ToSchema (Maybe inner) needs ToSchema inner. Expected DateTime should have a ToS

type: buggood first issuepackage: core
haskell-beam/beam634 Tier A · 63 pts
#824Opened 1 month ago
Benchmark build time of user code

Following the publication of Scarf moving away from Haskell, discussions mentioned that type-family-heavy code, like code using beam, can build slowly. I personally think that the tradeoff for this slower compilation is much, much more safety when interacting with the database. However, if we can preserve this safety and improve build times, we should! This ticket is about creating a benchmark for building a beam-based application. Improvements to build times can follow separately.

enhancementhelp wanted
hadolint/hadolint12,366 Tier A · 69 pts
#1217Opened 1 month ago
Install on Windows via Winget support

Please consider adding hadolint on winget.

help wantedpackagingplatform/windows
1
haskell-beam/beam634 Tier A · 63 pts
#822Opened 1 month ago
Resurrecting the MySQL backend

MySQL remains a serious choice over Postgres in many domains. We should support it. There exists a beam-mysql, but it is unmaintained. beam-mysql is based on mysql, which is also unmaintained. We should: import beam-mysql in this repo; Switch over to use mysql-haskell, which is maintained I'm a little oversubscribed at the moment, but I'm happy to review pull requests!

enhancementhelp wanted
1
GaloisInc/saw-script517 Tier A · 70 pts
#3328Opened 1 month ago
Remove use of "irrefutable" incomplete matches and -Wno-incomplete-uni-patterns

The SAWScript typechecker and interpreter are built with -Wno-incomplete-uni-patterns and there's a long comment at the bottom of Typechecker.hs that explains why. Basically, there are a couple places that use irrefutable patterns with incomplete matches as a shortcut. These basically function as assertions that the omitted cases of the partial matches are not reached, which is fine until they are and then it turns out that the generated code throws UserError behind your back. That results in the following undesirable behavior: sawscript> let x = 3 saw-script/src/SAWScript/Typechecker.hs:2216:5-60: Non-exhaustive patterns in [(pat'', e1, s)] sawscript> IOW, it crashes but doesn't exit, and while it does print the Haskell source location, it doesn't print what the offending value was. This is not what we want; the handful of affected cases should be turned into explicit panics that print useful messages. We can afford a couple extra lines of code for that in a project the size of SA

type: bugeasysubsystem: saw-script
2
gren-lang/compiler498 Tier B · 50 pts
#380Opened 2 months ago
Haskell-based compiler 0.6.5 crashes when compiling a package that has a summary field >= 80 chars

Example: { "type": "package", "platform": "common", "name": "example/package", "license": "BSD-3-Clause", "summary": "this summary line is not that long... but it is longer than expected at 80 chars", "source-directories": [ "src" ], "version": "1.0.0", "exposed-modules": [ "Main" ], "gren-version": "0.6.0 <= v < 0.7.0", "dependencies": { "gren-lang/core": "7.4.0 <= v < 8.0.0" } } "gren make" produces: gren: DecodeProblem "{\"command\":\"make\",\"optimize\":false,\"sourcemap .... <snipped> \"summary\":\"this summary line is not that long... but it is longer than expected at 80 chars\" <snipped> (Field "project-outline" (Field "summary" (Failure (Region (Position 1 266) (Position 1 348)) InvalidInput))) CallStack (from HasCallStack): error, called at terminal/Main.hs:30:13 in gren-0.6.5-inplace-gren:Main HasCallStack backtrace: collectBacktraces, called at libraries/ghc-internal/src/GHC/Internal/Excep

buggood first issuehelp wanted
turion/rhine144 Tier B · 51 pts
#448Opened 2 months ago
Use Selective instead of Monad in many basic stream constructs

Many stream primitives can probably be rewritten with Selective since they only bind on a case distinction.

good first issue
1
Plutonomicon/plutarch-plutus133 Tier A · 70 pts
#1003Opened 2 months ago
Improve Cabal file and defaults

Our current default warning and language settings are a bit ridiculous. Lots of things are globally on for no reason, lots of things are globally off for no reason, and there's no reasonable structure to what is on or off. The Cabal file should be organized better, and the defaults should be improved.

enhancementhelp wanted
1
GaloisInc/saw-script517 Tier A · 70 pts
#3312Opened 2 months ago
`saw --help` returns exit code 2

When you run saw --help, it returns exit code 2: $ saw --help <snip> $ echo $? 2 This is a bit unfortunate, as I sometimes use saw --help as a basic smoke test to verify if saw can run at all on a given machine, but the non-zero exit code makes scripts believe that saw --help isn't working as expected. Any objections to changing the behavior to return exit code 0 instead?

type: bugeasy
1
jonascarpay/apecs421 Tier B · 55 pts
#159Opened 2 months ago
Dynamically-sized cache store
enhancementgood first issue
jonascarpay/apecs421 Tier B · 55 pts
#157Opened 2 months ago
Restore windows builds on CI
help wanted
turion/rhine144 Tier B · 51 pts
#435Opened 2 months ago
Generalise concatS to Foldable

Right now it is specialised to lists: concatS :: (Monad m) => StreamT m [a] -> StreamT m a I believe it could be: concatS :: (Monad m, Foldable t) => StreamT m (t a) -> StreamT m a Same for the automaton version.

good first issueautomaton
well-typed/haskell-debugger146 Tier A · 64 pts
#328Opened 2 months ago
Mention Zed is supported in the README

Someone has kindly prepared support for Zed in the Zed Haskell Extension. It'd be good to reference it from the readme (Along with support for VScode, vim, emacs)

help wantednewcomer 🌱dap-client
2
cardano-scaling/hydra336 Tier A · 62 pts
#2707Opened 2 months ago
`ContestationPeriod` `Num` instance can panic via `(-)` / `negate`

Description (-) and negate over Natural throw Underflow on negative results. fromInteger 0 correctly rejects zero, but 1 - 2 :: ContestationPeriod silently produces a runtime exception rather than a typed failure. The on-chain protocol assumes cp > 0; the type intends to enforce this but exposes ways to violate it that panic instead of returning Maybe. Location: hydra-tx/src/Hydra/Tx/ContestationPeriod.hs:28-38. Verification Read the Num instance; both operators delegate to Natural which throws on underflow. Suggested fix Remove the Num instance, or implement (-) and negate as error "use fromNominalDiffTime". Only legitimate constructors are fromInteger >0 and fromNominalDiffTime.

good first issueclaude
cardano-scaling/hydra336 Tier A · 62 pts
#2704Opened 2 months ago
`DecrementObservation.distributedUTxO` pairs spent TxIns with new outputs

Description UTxO.fromList $ zip (txIns' tx) outputs zips the transaction's spent inputs with the freshly-produced decommit outputs. The resulting TxIn keys reference the head/fee-input UTxOs, not the new outputs. Latent bug since downstream consumers only read outputsOfUTxO, but any indexer/client touching the TxIns sees ghost references. Location: hydra-tx/src/Hydra/Tx/Decrement.hs:130-137. Verification Read the observation builder; compared with observeFanoutTx/observeFinalPartialFanoutTx which correctly use mkTxIn tx <$> [0..]. Suggested fix Replace inputs = txIns' tx with inputs = mkTxIn tx <$> [1..] (decommit outputs start at index 1; head output is index 0).

good first issueclaude
cardano-scaling/hydra336 Tier A · 62 pts
#2703Opened 2 months ago
incrementTx` crashes on empty `depositScriptUTxO` via `List.head`

Description (depositIn, _) = List.head $ UTxO.toList depositScriptUTxO. If a caller passes an empty depositScriptUTxO (e.g. lookup failure), the node aborts at tx-construction time with Prelude.head: empty list. The comment guarantees "single output" but the code silently ignores extras. Location: hydra-tx/src/Hydra/Tx/Increment.hs:103. Verification Read the call site; List.head is unguarded. Suggested fix Take the deposit input as (TxIn, TxOut CtxUTxO) directly (mirroring the head-input convention), or return Either Text Tx. At minimum, pattern-match and error with a useful message.

good first issueclaude
cardano-scaling/hydra336 Tier A · 62 pts
#2693Opened 2 months ago
`validateRunOptions` accepts empty `hydraScriptsTxId` and skips network cross-check

Description cardanoChainConfigParser allows hydraScriptsTxId = [] (the many alternative succeeds with empty). validateNetwork checks only the literal network name; nothing requires --network to match --mainnet/--testnet-magic. Misconfigurations fail far from the CLI line (queryScriptRegistry []) or silently submit to the wrong chain. Location: hydra-node/src/Hydra/Options.hs:459-481, 795-809, 935-944. Verification Read the parser chain and validateRunOptions; neither check exists. Suggested fix Add Cardano … && null hydraScriptsTxId → Left MissingHydraScriptsTxId. Require --network mainnet paired with the Mainnet networkId (and similarly for preview/preprod via magic numbers).

good first issueclaude
cardano-scaling/hydra336 Tier A · 62 pts
#2692Opened 2 months ago
`--monitoring-port` binds all interfaces, no `--monitoring-host`

Description withMonitoring calls serveMetrics (fromIntegral monitoringPort) ["metrics"] (sample registry), which runs Warp on the wildcard host. By contrast --api-host defaults to 127.0.0.1. Operators expecting localhost-only consistency don't get it; head-related counters (snapshot counts, tx counts) leak to anyone who can reach the port. Location: hydra-node/src/Hydra/Options.hs:711-720, Logging/Monitoring.hs:46-55. Verification Read withMonitoring; no setHost applied. CLI has no --monitoring-host option. Suggested fix Add a --monitoring-host option (default 127.0.0.1) symmetric with --api-host, threaded into Logging.Monitoring to apply Warp.setHost.

good first issueclaude
cardano-scaling/hydra336 Tier A · 62 pts
#2687Opened 2 months ago
`Authenticated` envelope drops the signature

Description Authenticated msg = { payload, party }. Signatures are discarded after verify. wireNetworkInput feeds only (party, msg) into HeadLogic; persistence stores ReceivedMessage{sender, msg}. If a head later disputes whether peer X actually authored a particular AckSn, no on-disk evidence remains to re-prove authorship to a third party. Location: hydra-node/src/Hydra/Network/Authenticate.hs:31-35, Hydra/Node.hs:240-247. Verification Read the Authenticated definition and ReceivedMessage persistence; signature is not carried. Suggested fix Keep the signature in Authenticated (or store the raw Signed blob in the event log) so audit/replay analysis can verify authorship after the fact.

good first issueclaude
cardano-scaling/hydra336 Tier A · 62 pts
#2686Opened 2 months ago
`mkThreadId` silently returns 0 on parse failure

Description mkThreadId = fromMaybe 0 . readMaybe . Text.unpack . Text.drop 9 . show relies on show of a ThreadId matching "ThreadId N". If GHC ever changes the Show instance (or in IOSim-style monads), every log line gets threadId: 0 and traces from different threads become indistinguishable. Location: hydra-node/src/Hydra/Logging.hs:154-162. Verification Read the parse expression; brittle to upstream string-format changes. Suggested fix On parse failure, hash the displayed form (or use the displayed string verbatim) to keep cross-thread distinguishability. Alternatives considered Use myThreadId from a MonadThread abstraction: bigger refactor.

good first issueclaude
cardano-scaling/hydra336 Tier A · 62 pts
#2683Opened 2 months ago
Missing test - `SeenSnapshot.signableBytes` JSON roundtrip

Description signableBytes is excluded from JSON encoding and reconstructed via mkSeenSnapshot on decode. No test asserts that after a JSON roundtrip the resulting SeenSnapshot still accepts the same AckSn signatures as before. An accidental divergence between getSignableRepresentation snapshot at sign-time vs decode-time would silently brick snapshot confirmation post-restart. Location: hydra-node/src/Hydra/HeadLogic/State.hs:166-210. Verification Read the manual ToJSON/FromJSON/mkSeenSnapshot; no roundtrip property test exists in the suite. Suggested fix Add a property test (Aeson.decode . Aeson.encode = id) plus a signableBytes == getSignableRepresentation snapshot assertion in test/Hydra/HeadLogic/StateSpec.hs.

good first issueclaude
GaloisInc/saw-script517 Tier A · 70 pts
#3289Opened 3 months ago
x86 verification is missing `detectVacuity` support

llvm_verify, jvm_verify, mir_verify (as well as llvm_refine_spec) check the detectVacuity option and call Vacuity.checkAssumptionsForContradictions. There is no trace of this in the x86 code. That means if someone requests vacuity checking, it silently won't happen, which could end up being a quite expensive/frustrating detour for someone.

type: bugeasyneeds testusability

Top Haskell Repositories with Beginner Issues (0)

Updated Daily via GitHub GraphQL
No Haskell repositories indexed yet. Check back soon!

How to make your first Haskell open-source pull request

Finding approachable Good First Issues in Haskell allows you to build real-world software engineering experience. Instead of submitting PRs to abandoned repositories, GetMerged verifies maintainer review speeds and first-timer acceptance rates before you write a single line of code.

Select any issue above to claim it directly on GitHub, or click a repository to inspect full maintainer review turnaround metrics and triage guidance!

Get this week's top welcoming repos + fresh Good First Issues for Haskell

Free weekly email, scoped to Haskell. No account needed - confirm once and unsubscribe anytime.