diff --git a/config.json b/config.json
index 4f21bc3..07fd0d5 100644
--- a/config.json
+++ b/config.json
@@ -260,6 +260,14 @@
         "prerequisites": [],
         "difficulty": 2
       },
+      {
+        "slug": "strain",
+        "name": "Strain",
+        "uuid": "1306a71c-5ddb-4421-a119-c4b5f2f38efe",
+        "practices": [],
+        "prerequisites": [],
+        "difficulty": 2
+      },
       {
         "slug": "triangle",
         "name": "Triangle",
diff --git a/config.yaml b/config.yaml
index 40a5be2..fb135d0 100644
--- a/config.yaml
+++ b/config.yaml
@@ -239,6 +239,13 @@ exercises:
     prerequisites: []
     difficulty: 2
 
+  - slug: strain
+    name: Strain
+    uuid: 1306a71c-5ddb-4421-a119-c4b5f2f38efe
+    practices: []
+    prerequisites: []
+    difficulty: 2
+
   - slug: triangle
     name: Triangle
     uuid: 494f403b-3bd7-47f1-a866-d07e9faea677
diff --git a/exercises/practice/strain/.docs/instructions.md b/exercises/practice/strain/.docs/instructions.md
new file mode 100644
index 0000000..3469ae6
--- /dev/null
+++ b/exercises/practice/strain/.docs/instructions.md
@@ -0,0 +1,29 @@
+# Instructions
+
+Implement the `keep` and `discard` operation on collections.
+Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false.
+
+For example, given the collection of numbers:
+
+- 1, 2, 3, 4, 5
+
+And the predicate:
+
+- is the number even?
+
+Then your keep operation should produce:
+
+- 2, 4
+
+While your discard operation should produce:
+
+- 1, 3, 5
+
+Note that the union of keep and discard is all the elements.
+
+The functions may be called `keep` and `discard`, or they may need different names in order to not clash with existing functions or concepts in your language.
+
+## Restrictions
+
+Keep your hands off that filter/reject/whatchamacallit functionality provided by your standard library!
+Solve this one yourself using other basic tools instead.
diff --git a/exercises/practice/strain/.meta/.yamlscript/exercise.mk b/exercises/practice/strain/.meta/.yamlscript/exercise.mk
new file mode 100644
index 0000000..2506034
--- /dev/null
+++ b/exercises/practice/strain/.meta/.yamlscript/exercise.mk
@@ -0,0 +1 @@
+YS_VERSION := 0.1.75
diff --git a/exercises/practice/strain/.meta/Makefile b/exercises/practice/strain/.meta/Makefile
new file mode 100644
index 0000000..9314ec0
--- /dev/null
+++ b/exercises/practice/strain/.meta/Makefile
@@ -0,0 +1,28 @@
+SHELL := bash
+
+BASE := $(shell pwd)
+
+export YS_VERSION := 0.1.80
+
+YS_LOCAL_PREFIX := ../../../../.local/v$(YS_VERSION)
+
+YS_LOCAL_BIN := $(YS_LOCAL_PREFIX)/bin
+
+YS_BIN := $(YS_LOCAL_BIN)/ys-$(YS_VERSION)
+
+TEST_FILE ?= $(wildcard *-test.ys)
+
+
+export PATH := $(YS_LOCAL_BIN):$(PATH)
+
+export YSPATH := $(BASE)
+
+
+default:
+
+test: $(YS_BIN)
+	prove -v $(TEST_FILE)
+
+$(YS_BIN):
+	curl -s https://yamlscript.org/install | \
+	  BIN=1 VERSION=$(YS_VERSION) PREFIX=$(YS_LOCAL_PREFIX) bash >/dev/null
diff --git a/exercises/practice/strain/.meta/config.json b/exercises/practice/strain/.meta/config.json
new file mode 100644
index 0000000..a4c2cee
--- /dev/null
+++ b/exercises/practice/strain/.meta/config.json
@@ -0,0 +1,23 @@
+{
+  "authors": [
+    "ingydotnet"
+  ],
+  "files": {
+    "solution": [
+      "strain.ys"
+    ],
+    "test": [
+      "strain-test.ys",
+      "GNUmakefile",
+      "Makefile",
+      ".yamlscript/exercise.mk",
+      ".yamlscript/exercism-ys-installer"
+    ],
+    "example": [
+      ".meta/strain.ys"
+    ]
+  },
+  "blurb": "Implement the `keep` and `discard` operation on collections.",
+  "source": "Conversation with James Edward Gray II",
+  "source_url": "http://graysoftinc.com/"
+}
diff --git a/exercises/practice/strain/.meta/strain-test.ys b/exercises/practice/strain/.meta/strain-test.ys
new file mode 100644
index 0000000..1608436
--- /dev/null
+++ b/exercises/practice/strain/.meta/strain-test.ys
@@ -0,0 +1,125 @@
+#!/usr/bin/env ys-0
+
+require ys::taptest: :all
+
+use: strain
+
+test::
+- name: Keep on empty list returns empty list
+  code: keep([] \(true))
+  want: []
+  uuid: 26af8c32-ba6a-4eb3-aa0a-ebd8f136e003
+
+- name: Keeps everything
+  code: keep([1 3 5] \(true))
+  want:
+  - 1
+  - 3
+  - 5
+  uuid: f535cb4d-e99b-472a-bd52-9fa0ffccf454
+
+- name: Keeps nothing
+  code: keep([1 3 5] \(false))
+  want: []
+  uuid: 950b8e8e-f628-42a8-85e2-9b30f09cde38
+
+- name: Keeps first and last
+  code: keep([1 2 3] \((_ % 2) == 1))
+  want:
+  - 1
+  - 3
+  uuid: 92694259-6e76-470c-af87-156bdf75018a
+
+- name: Keeps neither first nor last
+  code: keep([1 2 3] \((_ % 2) == 0))
+  want:
+  - 2
+  uuid: 938f7867-bfc7-449e-a21b-7b00cbb56994
+
+- name: Keeps strings
+  code: keep(
+          qw(apple zebra banana zombies cherimoya zealot)
+          \(starts?(_ 'z')))
+  want:
+  - zebra
+  - zombies
+  - zealot
+  uuid: 8908e351-4437-4d2b-a0f7-770811e48816
+
+- name: Keeps lists
+  code: keep(
+          [[1 2 3] [5 5 5] [5 1 2] [2 1 2] [1 5 2] [2 2 1] [1 2 5]]
+          \(has?(_ 5)))
+  want:
+  - - 5
+    - 5
+    - 5
+  - - 5
+    - 1
+    - 2
+  - - 1
+    - 5
+    - 2
+  - - 1
+    - 2
+    - 5
+  uuid: 2728036b-102a-4f1e-a3ef-eac6160d876a
+
+- name: Discard on empty list returns empty list
+  code: discard([] \(true))
+  want: []
+  uuid: ef16beb9-8d84-451a-996a-14e80607fce6
+
+- name: Discards everything
+  code: discard([1 3 5] \(true))
+  want: []
+  uuid: 2f42f9bc-8e06-4afe-a222-051b5d8cd12a
+
+- name: Discards nothing
+  code: discard([1 3 5] \(false))
+  want:
+  - 1
+  - 3
+  - 5
+  uuid: ca990fdd-08c2-4f95-aa50-e0f5e1d6802b
+
+- name: Discards first and last
+  code: discard([1 2 3] \((_ % 2) == 1))
+  want:
+  - 2
+  uuid: 71595dae-d283-48ca-a52b-45fa96819d2f
+
+- name: Discards neither first nor last
+  code: discard([1 2 3] \((_ % 2) == 0))
+  want:
+  - 1
+  - 3
+  uuid: ae141f79-f86d-4567-b407-919eaca0f3dd
+
+- name: Discards strings
+  code: discard(
+          qw(apple zebra banana zombies cherimoya zealot)
+          \(starts?(_ 'z')))
+  want:
+  - apple
+  - banana
+  - cherimoya
+  uuid: daf25b36-a59f-4f29-bcfe-302eb4e43609
+
+- name: Discards lists
+  code: discard(
+          [[1 2 3] [5 5 5] [5 1 2] [2 1 2] [1 5 2] [2 2 1] [1 2 5]]
+          \(has?(_ 5)))
+  want:
+  - - 1
+    - 2
+    - 3
+  - - 2
+    - 1
+    - 2
+  - - 2
+    - 2
+    - 1
+  uuid: a38d03f9-95ad-4459-80d1-48e937e4acaf
+
+done: 14
diff --git a/exercises/practice/strain/.meta/strain.ys b/exercises/practice/strain/.meta/strain.ys
new file mode 100644
index 0000000..ce5a740
--- /dev/null
+++ b/exercises/practice/strain/.meta/strain.ys
@@ -0,0 +1,7 @@
+!yamlscript/v0
+
+defn keep(list predicate):
+  mapcat \(when(predicate(_) [_])): list
+
+defn discard(list predicate):
+  mapcat \(when-not(predicate(_) [_])): list
diff --git a/exercises/practice/strain/.meta/tests.toml b/exercises/practice/strain/.meta/tests.toml
new file mode 100644
index 0000000..3a617b4
--- /dev/null
+++ b/exercises/practice/strain/.meta/tests.toml
@@ -0,0 +1,52 @@
+# This is an auto-generated file.
+#
+# Regenerating this file via `configlet sync` will:
+# - Recreate every `description` key/value pair
+# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
+# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
+# - Preserve any other key/value pair
+#
+# As user-added comments (using the # character) will be removed when this file
+# is regenerated, comments can be added via a `comment` key.
+
+[26af8c32-ba6a-4eb3-aa0a-ebd8f136e003]
+description = "keep on empty list returns empty list"
+
+[f535cb4d-e99b-472a-bd52-9fa0ffccf454]
+description = "keeps everything"
+
+[950b8e8e-f628-42a8-85e2-9b30f09cde38]
+description = "keeps nothing"
+
+[92694259-6e76-470c-af87-156bdf75018a]
+description = "keeps first and last"
+
+[938f7867-bfc7-449e-a21b-7b00cbb56994]
+description = "keeps neither first nor last"
+
+[8908e351-4437-4d2b-a0f7-770811e48816]
+description = "keeps strings"
+
+[2728036b-102a-4f1e-a3ef-eac6160d876a]
+description = "keeps lists"
+
+[ef16beb9-8d84-451a-996a-14e80607fce6]
+description = "discard on empty list returns empty list"
+
+[2f42f9bc-8e06-4afe-a222-051b5d8cd12a]
+description = "discards everything"
+
+[ca990fdd-08c2-4f95-aa50-e0f5e1d6802b]
+description = "discards nothing"
+
+[71595dae-d283-48ca-a52b-45fa96819d2f]
+description = "discards first and last"
+
+[ae141f79-f86d-4567-b407-919eaca0f3dd]
+description = "discards neither first nor last"
+
+[daf25b36-a59f-4f29-bcfe-302eb4e43609]
+description = "discards strings"
+
+[a38d03f9-95ad-4459-80d1-48e937e4acaf]
+description = "discards lists"
diff --git a/exercises/practice/strain/.yamlscript/exercise.mk b/exercises/practice/strain/.yamlscript/exercise.mk
new file mode 100644
index 0000000..2506034
--- /dev/null
+++ b/exercises/practice/strain/.yamlscript/exercise.mk
@@ -0,0 +1 @@
+YS_VERSION := 0.1.75
diff --git a/exercises/practice/strain/.yamlscript/exercism-ys-installer b/exercises/practice/strain/.yamlscript/exercism-ys-installer
new file mode 100644
index 0000000..ae3fa01
--- /dev/null
+++ b/exercises/practice/strain/.yamlscript/exercism-ys-installer
@@ -0,0 +1,127 @@
+#!/env/bin/env bash
+
+set -euo pipefail
+
+intro-prompt() (
+  cat <<...
+--------------------------------------------------------------------------------
+
+This YAMLScript Exercism exercise requires the YAMLScript version $version
+interpreter command file to be installed here:
+
+  $prefix/bin/ys
+
+You can install it by pressing Enter now, or by running this command:
+
+  $make install-ys
+
+This should only take a few seconds and you only need to do this once.
+Other exercises will use the same file.
+
+See https://yamlscript.org/doc/install/ for more YAMLScript installation info.
+
+--------------------------------------------------------------------------------
+
+Would you like to install the 'ys' file now?
+
+...
+
+  printf "Press Enter to install. Ctl-C to Quit."; read -r
+)
+
+main() {
+  setup "$@"
+
+  install-from-local
+
+  $auto && intro-prompt
+
+  installed || install-from-release || true
+  installed || install-from-build || true
+  installed ||
+    die "Installing '$installed' failed. Giving up." \
+        "Consider filing an issue at: $gh_issue_url"
+
+  echo
+  echo 'Success!'
+  echo "$installed is now installed."
+  echo
+}
+
+installed() {
+  [[ -f $installed ]]
+}
+
+install-from-local() {
+  local path
+  path=$(command -v "$ysfq") || true
+  if [[ -f $path ]]; then
+    mkdir -p "$bin"
+    cp "$path" "$bin"/
+    ln -fs "$ysfq" "$bin/ys-0"
+    ln -fs "$ysfq" "$bin/ys"
+    (installed && $auto) && exit
+    true
+  fi
+}
+
+install-from-release() (
+  set -x
+  curl -s https://yamlscript.org/install |
+    BIN=1 VERSION="$version" PREFIX="$prefix" bash
+)
+
+install-from-build() (
+  cat <<...
+
+The binary release installation failed.
+We can attempt to build and install $ysfq now.
+This can take from 1 to 5 minutes to complete.
+
+...
+
+  printf "Press Enter to install. Ctl-C to Quit."; read -r
+
+  [[ -d /tmp && -w /tmp ]] ||
+    die "Can't write to /tmp" \
+        'Giving up.'
+
+  set -x
+
+  rm -fr "$yamlscript_clone"
+
+  git clone --branch="$version" "$yamlscript_repo" "$yamlscript_clone"
+
+  "$make" -C "$yamlscript_clone/ys" install PREFIX="$prefix"
+)
+
+setup() {
+  version=$1
+  prefix=$2
+  make=$3
+  auto=false
+  [[ ${4-} ]] && auto=true
+
+  [[ $version =~ ^0\.1\.[0-9]+$ ]] ||
+    die "Invalid YS_VERSION '$version'"
+
+  bin=$prefix/bin
+  ysfq=ys-$version
+  installed=$bin/$ysfq
+
+  if installed; then
+    echo "'$installed' is already installed."
+    exit
+  fi
+
+  yamlscript_repo=https://github.com/yaml/yamlscript
+  yamlscript_clone=/tmp/yamlscript-exercism
+  gh_issue_url=https://github.com/exercism/yamlscript/issues
+}
+
+die() {
+  printf '%s\n' "$@" >&2
+  exit 1
+}
+
+main "$@"
diff --git a/exercises/practice/strain/GNUmakefile b/exercises/practice/strain/GNUmakefile
new file mode 100644
index 0000000..78a395a
--- /dev/null
+++ b/exercises/practice/strain/GNUmakefile
@@ -0,0 +1,49 @@
+SHELL := bash
+
+BASE := $(shell pwd)
+
+export YS_VERSION := 0.1.80
+
+YS_LOCAL_PREFIX := ../../../.local/v$(YS_VERSION)
+ifeq (,$(shell [[ -d "$(YS_LOCAL_PREFIX)" ]] && echo ok))
+YS_LOCAL_PREFIX := $(shell cd .. && pwd -P)/.local/v$(YS_VERSION)
+endif
+
+YS_LOCAL_BIN := $(YS_LOCAL_PREFIX)/bin
+YS_BIN := $(YS_LOCAL_BIN)/ys-$(YS_VERSION)
+
+YS_INSTALLER := .yamlscript/exercism-ys-installer
+YS_INSTALLER_CMD := \
+  bash $(YS_INSTALLER) $(YS_VERSION) $(YS_LOCAL_PREFIX) $(MAKE)
+
+TEST_FILE ?= $(wildcard *-test.ys)
+
+export PATH := $(YS_LOCAL_BIN):$(PATH)
+export YSPATH := $(BASE)
+
+
+#-------------------------------------------------------------------------------
+default:
+	@echo " No default make rule. Try 'make test'."
+
+test: $(YS_BIN)
+	prove -v $(TEST_FILE)
+
+install-ys:
+	@$(YS_INSTALLER_CMD)
+
+uninstall-ys:
+	rm -fr $(YS_LOCAL_PREFIX)
+
+
+#-------------------------------------------------------------------------------
+ifdef EXERCISM_YAMLSCRIPT_GHA
+$(YS_BIN):
+
+else ifeq (/mnt/,$(dir $(BASE)))
+$(YS_BIN):
+
+else
+$(YS_BIN):
+	@$(YS_INSTALLER_CMD) auto
+endif
diff --git a/exercises/practice/strain/Makefile b/exercises/practice/strain/Makefile
new file mode 100644
index 0000000..06b6f00
--- /dev/null
+++ b/exercises/practice/strain/Makefile
@@ -0,0 +1,8 @@
+# This Makefile is a decoy to attempt to detect when a non-GNU make is being
+# used and alert the user.
+
+test:
+	@echo "You appear to be using a non-GNU version of the 'make' program."
+	@echo "The YAMLScript Exercism track requires you to use GNU make."
+	@echo "Please try 'make $@' again using GNU make."
+	@exit 1
diff --git a/exercises/practice/strain/strain-test.ys b/exercises/practice/strain/strain-test.ys
new file mode 100644
index 0000000..45fbd6b
--- /dev/null
+++ b/exercises/practice/strain/strain-test.ys
@@ -0,0 +1,111 @@
+#!/usr/bin/env ys-0
+
+require ys::taptest: :all
+
+use: strain
+
+test::
+- name: Keep on empty list returns empty list
+  code: keep([] "fn([x] true)")
+  want: []
+
+- name: Keeps everything
+  code: keep([1 3 5] "fn(x):\ true")
+  want:
+  - 1
+  - 3
+  - 5
+
+- name: Keeps nothing
+  code: keep([1 3 5] "fn(x):\ false")
+  want: []
+
+- name: Keeps first and last
+  code: keep([1 2 3] "fn(x):\ (x % 2) == 1")
+  want:
+  - 1
+  - 3
+
+- name: Keeps neither first nor last
+  code: keep([1 2 3] "fn(x):\ (x % 2) == 0")
+  want:
+  - 2
+
+- name: Keeps strings
+  code: keep(
+          qw(apple zebra banana zombies cherimoya zealot)
+          "fn(x):\ starts?(x, 'z')")
+  want:
+  - zebra
+  - zombies
+  - zealot
+
+- name: Keeps lists
+  code: keep(
+          [[1 2 3] [5 5 5] [5 1 2] [2 1 2] [1 5 2] [2 2 1] [1 2 5]]
+          "fn(x):\ has?(x, 5)")
+  want:
+  - - 5
+    - 5
+    - 5
+  - - 5
+    - 1
+    - 2
+  - - 1
+    - 5
+    - 2
+  - - 1
+    - 2
+    - 5
+
+- name: Discard on empty list returns empty list
+  code: discard([] "fn(x):\ true")
+  want: []
+
+- name: Discards everything
+  code: discard([1 3 5] "fn(x):\ true")
+  want: []
+
+- name: Discards nothing
+  code: discard([1 3 5] "fn(x):\ false")
+  want:
+  - 1
+  - 3
+  - 5
+
+- name: Discards first and last
+  code: discard([1 2 3] "fn(x):\ (x % 2) == 1")
+  want:
+  - 2
+
+- name: Discards neither first nor last
+  code: discard([1 2 3] "fn(x):\ (x % 2) == 0")
+  want:
+  - 1
+  - 3
+
+- name: Discards strings
+  code: discard(
+          qw(apple zebra banana zombies cherimoya zealot)
+          "fn(x):\ starts?(x, 'z')")
+  want:
+  - apple
+  - banana
+  - cherimoya
+
+- name: Discards lists
+  code: discard(
+          [[1 2 3] [5 5 5] [5 1 2] [2 1 2] [1 5 2] [2 2 1] [1 2 5]]
+          "fn(x):\ has?(x, 5)")
+  want:
+  - - 1
+    - 2
+    - 3
+  - - 2
+    - 1
+    - 2
+  - - 2
+    - 2
+    - 1
+
+done: 14
diff --git a/exercises/practice/strain/strain.ys b/exercises/practice/strain/strain.ys
new file mode 100644
index 0000000..c1dfef9
--- /dev/null
+++ b/exercises/practice/strain/strain.ys
@@ -0,0 +1,7 @@
+!yamlscript/v0
+
+defn keep(list predicate):
+  # Implement the 'keep' function.
+
+defn discard(list predicate):
+  # Implement the 'discard' function.