diff --git a/darcs-beta.cabal b/darcs-beta.cabal
--- a/darcs-beta.cabal
+++ b/darcs-beta.cabal
@@ -1,5 +1,5 @@
 Name: darcs-beta
-version:        2.4.98.5
+version:        2.4.99.1
 License:        GPL
 License-file:   COPYING
 Author:         David Roundy <droundy@darcs.net>, <darcs-users@darcs.net>
@@ -157,7 +157,8 @@
                       System.Posix.IO
       cpp-options:    -DWIN32
       c-sources:      src/win32/send_email.c
-      build-depends:  unix-compat >= 0.1.2
+      build-depends:  unix-compat >= 0.1.2,
+                      regex-posix >= 0.94.4 && < 0.95
 
     build-depends:   base          < 5,
                      extensible-exceptions >= 0.1 && < 0.2,
@@ -355,7 +356,8 @@
                       System.Posix.Files
                       System.Posix.IO
       cpp-options:    -DWIN32
-      build-depends:  unix-compat >= 0.1.2
+      build-depends:  unix-compat >= 0.1.2,
+                      regex-posix >= 0.94.4 && < 0.95
 
     if os(solaris)
       cc-options:     -DHAVE_SIGINFO_H
@@ -495,7 +497,8 @@
                     Preproc
     cpp-options:    -DWIN32
     c-sources:      src/win32/send_email.c
-    build-depends:  unix-compat >= 0.1.2
+    build-depends:  unix-compat >= 0.1.2,
+                    regex-posix >= 0.94.4 && < 0.95
 
   if os(solaris)
     cc-options:     -DHAVE_SIGINFO_H
@@ -642,7 +645,8 @@
                       System.Posix.IO
       cpp-options:    -DWIN32
       c-sources:      src/win32/send_email.c
-      build-depends:  unix-compat >= 0.1.2
+      build-depends:  unix-compat >= 0.1.2,
+                      regex-posix >= 0.94.4 && < 0.95
 
     if os(solaris)
       cc-options:     -DHAVE_SIGINFO_H
diff --git a/release/distributed-context b/release/distributed-context
--- a/release/distributed-context
+++ b/release/distributed-context
@@ -1,1 +1,1 @@
-Just "\nContext:\n\n[TAG 2.4.98.5\nReinier Lamers <tux_rocker@reinier.de>**20100905170906\n Ignore-this: 848f746fa6a939cef069abe6722d4206\n] \n"
+Just "\nContext:\n\n[TAG 2.4.99.1\nReinier Lamers <tux_rocker@reinier.de>**20101015132045\n Ignore-this: 4293f06a5a3344bc710b65253ba0c8c1\n] \n"
diff --git a/src/Darcs/Arguments.lhs b/src/Darcs/Arguments.lhs
--- a/src/Darcs/Arguments.lhs
+++ b/src/Darcs/Arguments.lhs
@@ -119,8 +119,7 @@
 import Darcs.Repository.State ( restrictBoring, applyTreeFilter, readRecordedAndPending )
 import Darcs.URL ( isFile )
 import Darcs.RepoPath ( AbsolutePath, AbsolutePathOrStd, SubPath, toFilePath,
-                        makeSubPathOf, simpleSubPath,
-                        ioAbsolute, ioAbsoluteOrStd,
+                        makeSubPathOf, ioAbsolute, ioAbsoluteOrStd,
                         makeAbsolute, makeAbsoluteOrStd, rootDirectory )
 import Darcs.Patch.MatchData ( patchMatch )
 import Darcs.Flags ( DarcsFlag(..), maxCount, defaultFlag )
@@ -482,6 +481,16 @@
                 then toFilePath `fmap` fixFilePath opts f
                 else return f
 
+-- | @fixSubPaths files@ returns the @SubPath@s for the paths in @files@ that
+-- are inside the repository, preserving their order. Paths in @files@ that are
+-- outside the repository directory are not in the result.
+--
+-- When converting a relative path to an absolute one, this function first tries
+-- to interpret the relative path with respect to the current working directory.
+-- If that fails, it tries to interpret it with respect to the repository
+-- directory. Only when that fails does it omit the path from the result.
+--
+-- It is intended for validating file arguments to darcs commands.
 fixSubPaths :: [DarcsFlag] -> [FilePath] -> IO [SubPath]
 fixSubPaths flags fs =
     withCurrentDirectory o $
@@ -497,7 +506,11 @@
     fixit p = do ap <- ioAbsolute p
                  case makeSubPathOf r ap of
                    Just sp -> return $ Right sp
-                   Nothing -> return $ maybe (Left p) Right $ simpleSubPath p
+                   Nothing -> withCurrentDirectory r $ do
+                     absolutePathByRepodir <- ioAbsolute p
+                     return $ case makeSubPathOf r absolutePathByRepodir of
+                                Just sp -> Right sp
+                                Nothing -> Left p
 
 partitionEither :: [Either a b] -> ([b],[a])
 partitionEither es = ( [b | Right b <- es]
diff --git a/src/Darcs/Commands/Add.lhs b/src/Darcs/Commands/Add.lhs
--- a/src/Darcs/Commands/Add.lhs
+++ b/src/Darcs/Commands/Add.lhs
@@ -102,10 +102,10 @@
  do -- TODO do not expand here, and use findM/findIO or such later
     -- (needs adding to hashed-storage first though)
     cur <- expand =<< readRecordedAndPending repository
-    origfiles <- fixSubPaths opts args
-    when (null origfiles) $
+    when (null args) $
        putStrLn "Nothing specified, nothing added." >>
        putStrLn "Maybe you wanted to say `darcs add --recursive .'?"
+    origfiles <- fixSubPaths opts args
     let parlist = getParents cur (map toFilePath origfiles)
     flist' <- if Recursive `elem` opts
               then expandDirs origfiles
diff --git a/src/Darcs/Commands/Annotate.lhs b/src/Darcs/Commands/Annotate.lhs
--- a/src/Darcs/Commands/Annotate.lhs
+++ b/src/Darcs/Commands/Annotate.lhs
@@ -146,9 +146,12 @@
 that patch was applied.  If a directory and a tag name are given, the
 details of the patches involved in the specified tagged version will be output.
 \begin{code}
-annotateCmd opts args@[_] = withRepository opts $- \repository -> do
+annotateCmd opts [file] = withRepository opts $- \repository -> do
   r <- readRepo repository
-  (rel_file_or_directory:_) <- fixSubPaths opts args
+  fixed_args <- fixSubPaths opts [file]
+  (rel_file_or_directory:_) <- case fixed_args of
+                                 [] -> fail ("The supplied path " ++ file ++ " is not usable")
+                                 fs -> return fs
   let file_or_directory = rel_file_or_directory
   pinfo <- if haveNonrangeMatch opts
            then return $ patch2patchinfo `unseal2` (matchPatch opts r)
diff --git a/src/Darcs/Repository/DarcsRepo.lhs b/src/Darcs/Repository/DarcsRepo.lhs
--- a/src/Darcs/Repository/DarcsRepo.lhs
+++ b/src/Darcs/Repository/DarcsRepo.lhs
@@ -68,7 +68,7 @@
 import System.IO.Unsafe ( unsafeInterleaveIO )
 import System.FilePath.Posix ( (</>) )
 import Control.Monad ( when )
-import Darcs.Hopefully ( PatchInfoAnd,
+import Darcs.Hopefully ( Hopefully, PatchInfoAnd,
                          patchInfoAndPatch, info,
                          actually, hopefully, unavailable, n2pia )
 import Darcs.SignalHandler ( withSignalsBlocked )
@@ -104,7 +104,7 @@
 import Darcs.Utils ( catchall )
 import Darcs.ProgressPatches ( progressFL )
 import Printer ( text, (<>), Doc, ($$), empty )
-import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal, unseal )
+import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal, unseal, mapSeal )
 
 #include "impossible.h"
 \end{code}
@@ -189,6 +189,7 @@
 addToTentativeInventory opts p =
     do appendDocBinFile (darcsdir++"/tentative_inventory") $ text "\n"
                             <> showPatchInfo (patch2patchinfo p)
+       res <- writePatch opts p
        when (isTag $ patch2patchinfo p) $
             do debugMessage "Optimizing the tentative inventory, since we're adding a tag."
                realdir <- toPath `fmap` ioAbsoluteOrRemote "."
@@ -197,7 +198,7 @@
                Sealed ps <- readRepoPrivate k realdir "tentative_inventory"
                             :: IO  (SealedPatchSet p C(Origin) )
                simplyWriteInventory "tentative_inventory" "." $ slightlyOptimizePatchset ps
-       writePatch opts p
+       return res
 
 addToTentativePristine :: Effect p => p C(x y) -> IO ()
 addToTentativePristine p =
@@ -310,15 +311,13 @@
                  return $ seal $ Tagged tag00 Nothing ps :<: ts
           parse2 :: RepoPatch p => PatchInfo -> FilePath
                                 -> IO (Sealed (PatchInfoAnd p C(x)))
-          parse2 i fn = do ps <- gzFetchFilePS fn Cachable
-                           return $ hopefullyNoParseError i (toPath fn) (readPatch ps)
-          hopefullyNoParseError :: PatchInfo -> String
-                                -> Maybe (Sealed (Named a1dr C(x)), b)
-                                -> Sealed (PatchInfoAnd a1dr C(x))
-          hopefullyNoParseError i _ (Just (Sealed x, _)) =
-              seal $ patchInfoAndPatch i $ actually x
-          hopefullyNoParseError i s Nothing =
-              seal $ patchInfoAndPatch i $ unavailable $ "Couldn't parse file "++s
+          parse2 i fn = do ps <- unsafeInterleaveIO $ gzFetchFilePS fn Cachable
+                           return $ patchInfoAndPatch i
+                             `mapSeal` hopefullyNoParseError (toPath fn) (readPatch ps)
+          hopefullyNoParseError :: String -> Maybe (Sealed (Named a1dr C(x)), b)
+                                -> Sealed (Hopefully (Named a1dr) C(x))
+          hopefullyNoParseError _ (Just (Sealed x, _)) = seal $ actually x
+          hopefullyNoParseError s Nothing = seal $ unavailable $ "Couldn't parse file "++s
           read_patches :: RepoPatch p =>
                           (FORALL(b) PatchInfo -> IO (Sealed (PatchInfoAnd p C(b))))
                        -> [PatchInfo] -> IO (Sealed (RL (PatchInfoAnd p) C(x)))
diff --git a/tests/issue1951-add-outside-repo.sh b/tests/issue1951-add-outside-repo.sh
new file mode 100644
--- /dev/null
+++ b/tests/issue1951-add-outside-repo.sh
@@ -0,0 +1,151 @@
+#!/usr/bin/env bash
+## Test for issue1951 - darcs should refuse adds from outside the
+## current repository
+##
+## Copyright (C) 2010 Eric Kow
+##
+## Permission is hereby granted, free of charge, to any person
+## obtaining a copy of this software and associated documentation
+## files (the "Software"), to deal in the Software without
+## restriction, including without limitation the rights to use, copy,
+## modify, merge, publish, distribute, sublicense, and/or sell copies
+## of the Software, and to permit persons to whom the Software is
+## furnished to do so, subject to the following conditions:
+##
+## The above copyright notice and this permission notice shall be
+## included in all copies or substantial portions of the Software.
+##
+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+## SOFTWARE.
+
+. lib                           # Load some portability helpers.
+
+rm -rf R R2 R3 R4 R5 R6 R7 R8 R9 R10
+darcs init      --repo R        # Create our test repos.
+darcs init      --repo R2
+darcs init      --repo R3
+darcs init      --repo R4
+darcs init      --repo R5
+darcs init      --repo R6
+darcs init      --repo R7
+darcs init      --repo R8
+darcs init      --repo R9
+darcs init      --repo R10
+
+# test if adding files outside the repository fails
+
+OUTSIDE=`pwd`
+
+cd R
+echo 'Example content.' > f
+echo 'Bad' > ../junk-for-issue1951
+darcs add f
+not darcs add ../junk-for-issue1951
+not darcs add $OUTSIDE/junk-for-issue1951
+darcs whatsnew > log
+not grep junk-for-issue1951 log
+cd ..
+
+# test adding a file that:
+#   * is in a subdirectory of the repository root
+#   * is referred to with a path relative to the cwd, when the cwd is the
+#     directory that the file is in
+cd R2
+mkdir subdir
+cd subdir
+touch f
+darcs add f
+darcs whatsnew > log
+grep 'subdir/f' log
+cd ../..
+
+# same as above, but now the relative path is valid both from the cwd and from
+# the repository root. Darcs should add the file in the cwd, not the one in the
+# repository root
+cd R3
+touch f
+mkdir subdir
+cd subdir
+touch f
+darcs add f
+darcs whatsnew > log
+grep 'subdir/f' log
+cd ../..
+
+# now test that adding fails on a file that
+#  * is in the repository root
+#  * is referred to with a path relative to the repository root, when the cwd is
+#    not the repository root
+cd R4
+touch myfilename
+mkdir subdir
+cd subdir
+not darcs add myfilename
+cd ../..
+
+# test adding a file by relative path from the repo root, when the cwd is
+# outside the repo
+# It may seem counterintuitive that this succeeds and the cases above and below
+# do not, but that's the way it is. We use this feature ourselves in our test
+# suite.
+
+touch R5/myfilename
+darcs add --repo R5 myfilename
+darcs whatsnew --repo R5 > log
+grep 'myfilename' log
+not grep '\.\./myfilename' log
+
+# The case below makes the R4 case (of using a repo-root-relative path in a
+# subdir of the repo) look even more like the R5 case (of using a
+# repo-root-relative path outside the repo) by usign the --repo flag. It still
+# failed on darcs 2.4.
+
+cd R6
+touch myfilename
+mkdir subdir
+cd subdir
+not darcs add --repo .. myfilename
+cd ../..
+
+# Test adding a file by relative path from the repo root, when the cwd is
+# outside the repo, and the relative path also exists from the cwd
+
+touch myfilename
+touch R7/myfilename
+darcs add --repo R7 myfilename
+darcs whatsnew --repo R7 > log
+grep 'myfilename' log
+not grep '\.\.myfilename' log
+
+# Like the R4 case: try to use a path relative to the repo root from a cwd that
+# is a subdir of the repo root. In this case the path relative to the repo root
+# also includes a directory however.
+
+cd R8
+mkdir subdir1
+mkdir subdir2
+touch subdir2/myfilename
+cd subdir1
+not darcs add subdir2/myfilename
+cd ../..
+
+# Try adding a non-repository file using a non-existent repo subdirectory name
+# followed by two ..'s
+touch myfilename
+cd R9
+not darcs add nonexistentsubdir/../../myfilename
+cd ..
+
+# Try adding a non-repository file using an existing repo subdirectory name
+# followed by two ..'s
+touch myfilename
+cd R10
+mkdir subdir
+not darcs add subdir/../../myfilename
+cd ..
