diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,7 @@
+# 0.8.0.0
+* Add `ProcessOptions`, replacing the primitive parameters of `Process` interpreters.
+* Add an option for `Process` that determines whether to kill the process after exiting the scope.
+
 # 0.6.0.0
 
 * Allow `Process` to emit custom chunks constructed by an interpreter of `ProcessOutput` instead of `ByteString`s
diff --git a/lib/Polysemy/Process.hs b/lib/Polysemy/Process.hs
--- a/lib/Polysemy/Process.hs
+++ b/lib/Polysemy/Process.hs
@@ -10,6 +10,8 @@
   recvError,
   send,
   withProcess,
+  ProcessOptions (ProcessOptions),
+  ProcessKill (..),
 
   -- ** ProcessOutput
   ProcessOutput,
@@ -57,6 +59,8 @@
 
 import Prelude hiding (send)
 
+import Polysemy.Process.Data.ProcessKill (ProcessKill (..))
+import Polysemy.Process.Data.ProcessOptions (ProcessOptions (ProcessOptions))
 import Polysemy.Process.Effect.Process (Process (..), recv, recvError, send, withProcess)
 import Polysemy.Process.Effect.ProcessOutput (ProcessOutput)
 import Polysemy.Process.Effect.Pty (Pty, withPty)
diff --git a/lib/Polysemy/Process/Data/ProcessKill.hs b/lib/Polysemy/Process/Data/ProcessKill.hs
new file mode 100644
--- /dev/null
+++ b/lib/Polysemy/Process/Data/ProcessKill.hs
@@ -0,0 +1,16 @@
+-- |Data type indicating whether to kill a process after exiting its scope.
+module Polysemy.Process.Data.ProcessKill where
+
+import Polysemy.Time (NanoSeconds)
+
+-- |Indicate whether to kill a process after exiting the scope in which it was used, if it hasn't terminated.
+data ProcessKill =
+  -- |Wait for the specified interval, then kill.
+  KillAfter NanoSeconds
+  |
+  -- |Kill immediately.
+  KillImmediately
+  |
+  -- |Wait indefinitely for the process to terminate.
+  KillNever
+  deriving stock (Eq, Show)
diff --git a/lib/Polysemy/Process/Data/ProcessOptions.hs b/lib/Polysemy/Process/Data/ProcessOptions.hs
new file mode 100644
--- /dev/null
+++ b/lib/Polysemy/Process/Data/ProcessOptions.hs
@@ -0,0 +1,21 @@
+-- |Data type containing options for processes.
+module Polysemy.Process.Data.ProcessOptions where
+
+import qualified Polysemy.Process.Data.ProcessKill as ProcessKill
+import Polysemy.Process.Data.ProcessKill (ProcessKill)
+
+-- |Controls the behaviour of 'Polysemy.Process.Process' interpreters.
+data ProcessOptions =
+  ProcessOptions {
+    -- |Whether to discard output chunks if the queue is full.
+    discard :: Bool,
+    -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
+    qsize :: Int,
+    -- |What to do if the process hasn't terminated when exiting the scope.
+    kill :: ProcessKill
+  }
+  deriving stock (Eq, Show)
+
+instance Default ProcessOptions where
+  def =
+    ProcessOptions True 1024 ProcessKill.KillImmediately
diff --git a/lib/Polysemy/Process/Interpreter/Process.hs b/lib/Polysemy/Process/Interpreter/Process.hs
--- a/lib/Polysemy/Process/Interpreter/Process.hs
+++ b/lib/Polysemy/Process/Interpreter/Process.hs
@@ -4,6 +4,7 @@
 module Polysemy.Process.Interpreter.Process where
 
 import Control.Concurrent.STM.TBMQueue (TBMQueue)
+import qualified Polysemy.Conc as Conc
 import Polysemy.Conc.Async (withAsync_)
 import qualified Polysemy.Conc.Data.QueueResult as QueueResult
 import qualified Polysemy.Conc.Effect.Queue as Queue
@@ -12,10 +13,12 @@
 import Polysemy.Conc.Effect.Scoped (Scoped)
 import Polysemy.Conc.Interpreter.Queue.TBM (interpretQueueTBMWith, withTBMQueue)
 import Polysemy.Conc.Interpreter.Scoped (interpretScopedResumableWith_)
-import Polysemy.Resume (Stop, resumeOr, stop, type (!!))
+import Polysemy.Resume (Stop, resumeOr, stop, type (!!), resuming)
 import Prelude hiding (fromException)
 
 import Polysemy.Process.Data.ProcessError (ProcessError (Terminated))
+import Polysemy.Process.Data.ProcessKill (ProcessKill (KillAfter, KillImmediately, KillNever))
+import Polysemy.Process.Data.ProcessOptions (ProcessOptions (ProcessOptions))
 import qualified Polysemy.Process.Effect.Process as Process
 import Polysemy.Process.Effect.Process (Process)
 import qualified Polysemy.Process.Effect.ProcessOutput as ProcessOutput
@@ -135,6 +138,30 @@
         _ ->
           unit
 
+handleKill ::
+  Members [SystemProcess, Race] r =>
+  ProcessKill ->
+  Sem r ()
+handleKill = \case
+  KillAfter interval ->
+    Conc.timeout_ SystemProcess.term interval (void SystemProcess.wait)
+  KillImmediately ->
+    SystemProcess.term
+  KillNever ->
+    void (dbgs =<< SystemProcess.wait)
+
+withKill ::
+  ∀ err r a .
+  Members [SystemProcess !! err, Resource, Race] r =>
+  ProcessKill ->
+  Sem r a ->
+  Sem r a
+withKill kill ma =
+  ma <* resuming @err @SystemProcess (\ _ -> dbg "resume") do
+    void SystemProcess.pid
+    dbg "killing"
+    handleKill kill
+
 type ScopeEffects o e err =
   [Queue (In ByteString), Queue (Out o), Queue (Err e), SystemProcess !! err]
 
@@ -142,15 +169,15 @@
   ∀ o e resource err r .
   Member (Scoped resource (SystemProcess !! err)) r =>
   Members [ProcessOutput e, ProcessOutput o, Resource, Race, Async, Embed IO] r =>
-  Bool ->
-  Int ->
+  ProcessOptions ->
   InterpretersFor (ScopeEffects o e err) r
-scope discard qSize =
+scope (ProcessOptions discard qSize kill) =
   withSystemProcess @resource .
   withQueues qSize .
   withAsync_ (outputQueue @Err @e @err discard SystemProcess.readStderr) .
   withAsync_ (outputQueue @Out @o @err discard SystemProcess.readStdout) .
-  withAsync_ (inputQueue @err SystemProcess.writeStdin)
+  withAsync_ (inputQueue @err SystemProcess.writeStdin) .
+  withKill @err kill
 
 -- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,
 -- deferring decoding of stdout and stderr to the interpreters of two 'ProcessOutput' effects.
@@ -158,27 +185,21 @@
   ∀ resource err o e r .
   Member (Scoped resource (SystemProcess !! err)) r =>
   Members [ProcessOutput o, ProcessOutput e, Resource, Race, Async, Embed IO] r =>
-  -- |Whether to discard output chunks if the queue is full or block.
-  Bool ->
-  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
-  Int ->
+  ProcessOptions ->
   InterpreterFor (Scoped () (Process ByteString o e) !! ProcessError) r
-interpretProcess discard qSize =
-  interpretScopedResumableWith_ @(ScopeEffects o e err) (scope @o @e @resource discard qSize) handleProcessWithQueues
+interpretProcess options =
+  interpretScopedResumableWith_ @(ScopeEffects o e err) (scope @o @e @resource options) handleProcessWithQueues
 
 -- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,
 -- producing 'ByteString's.
 interpretProcessByteString ::
   ∀ resource err r .
   Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r =>
-  -- |Whether to discard output chunks if the queue is full.
-  Bool ->
-  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
-  Int ->
+  ProcessOptions ->
   InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
-interpretProcessByteString discard qSize =
+interpretProcessByteString options =
   interpretProcessOutputId .
-  interpretProcess @resource @err discard qSize .
+  interpretProcess @resource @err options .
   raiseUnder
 
 -- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,
@@ -186,14 +207,11 @@
 interpretProcessByteStringLines ::
   ∀ resource err r .
   Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r =>
-  -- |Whether to discard output chunks if the queue is full.
-  Bool ->
-  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
-  Int ->
+  ProcessOptions ->
   InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
-interpretProcessByteStringLines discard qSize =
+interpretProcessByteStringLines options =
   interpretProcessOutputLines .
-  interpretProcess @resource @err discard qSize .
+  interpretProcess @resource @err options .
   raiseUnder
 
 -- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,
@@ -201,14 +219,11 @@
 interpretProcessText ::
   ∀ resource err r .
   Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r =>
-  -- |Whether to discard output chunks if the queue is full.
-  Bool ->
-  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
-  Int ->
+  ProcessOptions ->
   InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
-interpretProcessText discard qSize =
+interpretProcessText options =
   interpretProcessOutputText .
-  interpretProcess @resource @err discard qSize .
+  interpretProcess @resource @err options .
   raiseUnder
 
 -- |Interpret 'Process' with a system process resource whose file descriptors are connected to three 'TBMQueue's,
@@ -216,12 +231,9 @@
 interpretProcessTextLines ::
   ∀ resource err r .
   Members [Scoped resource (SystemProcess !! err), Resource, Race, Async, Embed IO] r =>
-  -- |Whether to discard output chunks if the queue is full.
-  Bool ->
-  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
-  Int ->
+  ProcessOptions ->
   InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
-interpretProcessTextLines discard qSize =
+interpretProcessTextLines options =
   interpretProcessOutputTextLines .
-  interpretProcess @resource @err discard qSize .
+  interpretProcess @resource @err options .
   raiseUnder
diff --git a/lib/Polysemy/Process/Interpreter/ProcessStdio.hs b/lib/Polysemy/Process/Interpreter/ProcessStdio.hs
--- a/lib/Polysemy/Process/Interpreter/ProcessStdio.hs
+++ b/lib/Polysemy/Process/Interpreter/ProcessStdio.hs
@@ -9,6 +9,7 @@
 import System.Process.Typed (ProcessConfig)
 
 import Polysemy.Process.Data.ProcessError (ProcessError)
+import Polysemy.Process.Data.ProcessOptions (ProcessOptions)
 import Polysemy.Process.Data.SystemProcessError (SystemProcessError)
 import Polysemy.Process.Effect.Process (Process)
 import Polysemy.Process.Interpreter.Process (
@@ -23,58 +24,46 @@
 interpretProcessByteStringNative ::
   Members [Resource, Race, Async, Embed IO] r =>
   -- |Whether to discard output chunks if the queue is full.
-  Bool ->
-  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
-  Int ->
-  -- |Basic config. The pipes will be changed to 'System.IO.Handle' by the interpreter.
+  ProcessOptions ->
   ProcessConfig () () () ->
   InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
-interpretProcessByteStringNative discard qSize conf =
+interpretProcessByteStringNative options conf =
   interpretSystemProcessNative conf .
-  interpretProcessByteString @PipesProcess @SystemProcessError discard qSize .
+  interpretProcessByteString @PipesProcess @SystemProcessError options .
   raiseUnder
 
 -- |Interpret 'Process' as a native 'Polysemy.Process.SystemProcess', producing lines of 'ByteString'.
 interpretProcessByteStringLinesNative ::
   Members [Resource, Race, Async, Embed IO] r =>
-  -- |Whether to discard output chunks if the queue is full.
-  Bool ->
-  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
-  Int ->
+  ProcessOptions ->
   -- |Basic config. The pipes will be changed to 'System.IO.Handle' by the interpreter.
   ProcessConfig () () () ->
   InterpreterFor (Scoped () (Process ByteString ByteString ByteString) !! ProcessError) r
-interpretProcessByteStringLinesNative discard qSize conf =
+interpretProcessByteStringLinesNative options conf =
   interpretSystemProcessNative conf .
-  interpretProcessByteStringLines @PipesProcess @SystemProcessError discard qSize .
+  interpretProcessByteStringLines @PipesProcess @SystemProcessError options .
   raiseUnder
 
 -- |Interpret 'Process' as a native 'Polysemy.Process.SystemProcess', producing unaccumulated chunks of 'Text'.
 interpretProcessTextNative ::
   Members [Resource, Race, Async, Embed IO] r =>
-  -- |Whether to discard output chunks if the queue is full.
-  Bool ->
-  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
-  Int ->
+  ProcessOptions ->
   -- |Basic config. The pipes will be changed to 'System.IO.Handle' by the interpreter.
   ProcessConfig () () () ->
   InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
-interpretProcessTextNative discard qSize conf =
+interpretProcessTextNative options conf =
   interpretSystemProcessNative conf .
-  interpretProcessText @PipesProcess @SystemProcessError discard qSize .
+  interpretProcessText @PipesProcess @SystemProcessError options .
   raiseUnder
 
 -- |Interpret 'Process' as a native 'Polysemy.Process.SystemProcess', producing lines of 'Text'.
 interpretProcessTextLinesNative ::
   Members [Resource, Race, Async, Embed IO] r =>
-  -- |Whether to discard output chunks if the queue is full.
-  Bool ->
-  -- |Maximum number of chunks allowed to be queued for each of the three standard pipes.
-  Int ->
+  ProcessOptions ->
   -- |Basic config. The pipes will be changed to 'System.IO.Handle' by the interpreter.
   ProcessConfig () () () ->
   InterpreterFor (Scoped () (Process ByteString Text Text) !! ProcessError) r
-interpretProcessTextLinesNative discard qSize conf =
+interpretProcessTextLinesNative options conf =
   interpretSystemProcessNative conf .
-  interpretProcessTextLines @PipesProcess @SystemProcessError discard qSize .
+  interpretProcessTextLines @PipesProcess @SystemProcessError options .
   raiseUnder
diff --git a/polysemy-process.cabal b/polysemy-process.cabal
--- a/polysemy-process.cabal
+++ b/polysemy-process.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           polysemy-process
-version:        0.7.0.0
+version:        0.8.0.0
 synopsis:       Polysemy Effects for System Processes
 description:    See <https://hackage.haskell.org/package/polysemy-process/docs/Polysemy-Process.html>
 category:       Concurrency
@@ -29,6 +29,8 @@
   exposed-modules:
       Polysemy.Process
       Polysemy.Process.Data.ProcessError
+      Polysemy.Process.Data.ProcessKill
+      Polysemy.Process.Data.ProcessOptions
       Polysemy.Process.Data.PtyError
       Polysemy.Process.Data.PtyResources
       Polysemy.Process.Data.SystemProcessError
@@ -114,6 +116,7 @@
     , polysemy >=1.6
     , polysemy-conc
     , polysemy-resume >=0.3
+    , polysemy-time >=0.4
     , posix-pty >=0.2
     , process
     , stm-chans >=2
@@ -202,6 +205,7 @@
     , polysemy-test
     , polysemy-time
     , tasty
+    , tasty-expected-failure
     , typed-process
   mixins:
       base hiding (Prelude)
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,15 +1,12 @@
 module Main where
 
-import Polysemy.Process.Test.ProcessTest (test_process)
-import Polysemy.Test (unitTest)
+import Polysemy.Process.Test.ProcessTest (test_processAll)
 import Test.Tasty (TestTree, defaultMain, testGroup)
 
 tests :: TestTree
 tests =
   testGroup "main" [
-    testGroup "process" [
-      unitTest "process" test_process
-    ]
+    test_processAll
   ]
 
 main :: IO ()
diff --git a/test/Polysemy/Process/Test/ProcessTest.hs b/test/Polysemy/Process/Test/ProcessTest.hs
--- a/test/Polysemy/Process/Test/ProcessTest.hs
+++ b/test/Polysemy/Process/Test/ProcessTest.hs
@@ -2,16 +2,21 @@
 
 module Polysemy.Process.Test.ProcessTest where
 
+import qualified Polysemy.Conc as Conc
 import Polysemy.Conc.Effect.Scoped (Scoped)
 import Polysemy.Conc.Interpreter.Race (interpretRace)
 import qualified Polysemy.Conc.Race as Race
 import Polysemy.Resume (resumeHoistError)
-import Polysemy.Test (UnitTest, runTestAuto, (===))
-import Polysemy.Time (Seconds (Seconds))
+import Polysemy.Test (UnitTest, assertLeft, runTestAuto, unitTest, (===))
+import Polysemy.Time (MilliSeconds (MilliSeconds), Seconds (Seconds))
 import qualified System.Process.Typed as Process
 import System.Process.Typed (ProcessConfig)
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.ExpectedFailure (ignoreTest)
 
 import Polysemy.Process.Data.ProcessError (ProcessError)
+import Polysemy.Process.Data.ProcessKill (ProcessKill (KillNever))
+import Polysemy.Process.Data.ProcessOptions (ProcessOptions (kill))
 import qualified Polysemy.Process.Effect.Process as Process
 import Polysemy.Process.Effect.Process (withProcess)
 import Polysemy.Process.Interpreter.ProcessStdio (interpretProcessByteStringNative, interpretProcessTextLinesNative)
@@ -30,7 +35,7 @@
 
 test_process :: UnitTest
 test_process =
-  runTestAuto $ interpretRace $ asyncToIOFinal $ interpretProcessByteStringNative True 10 config do
+  runTestAuto $ interpretRace $ asyncToIOFinal $ interpretProcessByteStringNative def config do
     response <- resumeHoistError @ProcessError @(Scoped _ _) show do
       withProcess do
         Process.send message
@@ -39,9 +44,29 @@
 
 test_processLines :: UnitTest
 test_processLines =
-  runTestAuto $ interpretRace $ asyncToIOFinal $ interpretProcessTextLinesNative True 10 config do
+  runTestAuto $ interpretRace $ asyncToIOFinal $ interpretProcessTextLinesNative def config do
     response <- resumeHoistError @ProcessError @(Scoped _ _) show do
       withProcess do
         Process.send message
         Race.timeout_ (throw "timed out") (Seconds 5) (replicateM 4 Process.recv)
     messageLines === response
+
+test_processKill :: UnitTest
+test_processKill =
+  runTestAuto $ interpretRace $ asyncToIOFinal $ interpretProcessTextLinesNative def { kill = KillNever } config do
+    result <- resumeHoistError @ProcessError @(Scoped _ _) show do
+      Conc.timeout unit (MilliSeconds 100) do
+        withProcess do
+          Process.send message
+          Process.recv
+    -- This does not succeed. It should be 'Left', but apparently the `timeout` causes the `SystemProcess` scope to stop
+    -- the process and makes the right side terminate regularly.
+    assertLeft () result
+
+test_processAll :: TestTree
+test_processAll =
+  testGroup "process" [
+    unitTest "process" test_process,
+    unitTest "process lines" test_processLines,
+    ignoreTest (unitTest "process kill" test_processKill)
+  ]
