diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,6 @@
+# Revision history for ogma-language-jsonspec
+
+## [1.2.0] - 2024-01-21
+
+* Version bump 1.2.0 (#117).
+* Initial release (#115).
diff --git a/LICENSE.pdf b/LICENSE.pdf
new file mode 100644
Binary files /dev/null and b/LICENSE.pdf differ
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/ogma-language-jsonspec.cabal b/ogma-language-jsonspec.cabal
new file mode 100644
--- /dev/null
+++ b/ogma-language-jsonspec.cabal
@@ -0,0 +1,82 @@
+-- Copyright 2024 United States Government as represented by the Administrator
+-- of the National Aeronautics and Space Administration. All Rights Reserved.
+--
+-- Disclaimers
+--
+-- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY
+-- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+-- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+-- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+-- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE
+-- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF
+-- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN
+-- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR
+-- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR
+-- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER,
+-- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING
+-- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES
+-- IT "AS IS." 
+--
+-- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST
+-- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS
+-- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN
+-- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE,
+-- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S
+-- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE
+-- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY
+-- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY
+-- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS
+-- AGREEMENT.
+
+cabal-version:       2.0
+build-type:          Simple
+
+name:                ogma-language-jsonspec
+version:             1.2.0
+homepage:            http://nasa.gov
+license:             OtherLicense
+license-file:        LICENSE.pdf
+author:              Ivan Perez, Alwyn Goodloe
+maintainer:          ivan.perezdominguez@nasa.gov
+category:            Aerospace
+extra-source-files:  CHANGELOG.md
+
+synopsis:            Ogma: Runtime Monitor translator: JSON Frontend
+
+description:         Ogma is a tool to facilitate the integration of safe runtime monitors into
+                     other systems. Ogma extends
+                     <https://github.com/Copilot-Language/copilot Copilot>, a high-level runtime
+                     verification framework that generates hard real-time C99 code.
+                     .
+                     This library contains a frontend to read specifications from JSON files.
+
+-- Ogma packages should be uncurated so that only the official maintainers make
+-- changes.
+--
+-- Because this is a NASA project, we want to make sure that users obtain
+-- exactly what we publish, unmodified by anyone external to our project.
+x-curation: uncurated
+
+library
+
+  exposed-modules:
+    Language.JSONSpec.Parser
+
+  build-depends:
+      base                   >= 4.11.0.0 && < 5
+    , aeson                  >= 2.0.0.0  && < 2.2
+    , jsonpath               >= 0.3      && < 0.4
+    , text
+    , megaparsec
+    , bytestring
+
+    , ogma-spec              >= 1.2.0 && < 1.3
+
+  hs-source-dirs:
+    src
+
+  default-language:
+    Haskell2010
+
+  ghc-options:
+    -Wall
diff --git a/src/Language/JSONSpec/Parser.hs b/src/Language/JSONSpec/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/JSONSpec/Parser.hs
@@ -0,0 +1,194 @@
+-- Copyright 2024 United States Government as represented by the Administrator
+-- of the National Aeronautics and Space Administration. All Rights Reserved.
+--
+-- Disclaimers
+--
+-- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY
+-- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+-- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+-- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+-- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE
+-- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF
+-- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN
+-- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR
+-- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR
+-- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER,
+-- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING
+-- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES
+-- IT "AS IS."
+--
+-- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST
+-- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS
+-- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN
+-- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE,
+-- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S
+-- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE
+-- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY
+-- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY
+-- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS
+-- AGREEMENT.
+--
+
+-- | Parser for Ogma specs stored in JSON files.
+module Language.JSONSpec.Parser where
+
+-- External imports
+import           Data.Aeson            (FromJSON (..), Value (..), decode, (.:))
+import           Data.Aeson.Key        (toString)
+import qualified Data.Aeson.KeyMap     as M
+import           Data.Aeson.Types      (prependFailure, typeMismatch)
+import           Data.Bifunctor        (first)
+import           Data.ByteString.Lazy  (fromStrict)
+import           Data.JSONPath.Execute
+import           Data.JSONPath.Parser
+import           Data.JSONPath.Types
+import           Data.Text             (pack, unpack)
+import qualified Data.Text             as T
+import qualified Data.Text.Encoding    as T
+import qualified Data.Text.IO          as T
+import           Text.Megaparsec       (eof, errorBundlePretty, parse)
+
+-- External imports: ogma-spec
+import Data.OgmaSpec
+
+data JSONFormat = JSONFormat
+  { specInternalVars    :: String
+  , specInternalVarId   :: String
+  , specInternalVarExpr :: String
+  , specInternalVarType :: String
+  , specExternalVars    :: String
+  , specExternalVarId   :: String
+  , specExternalVarType :: String
+  , specRequirements    :: String
+  , specRequirementId   :: String
+  , specRequirementDesc :: String
+  , specRequirementExpr :: String
+  }
+
+data JSONFormatInternal = JSONFormatInternal
+  { jfiInternalVars    :: [JSONPathElement]
+  , jfiInternalVarId   :: [JSONPathElement]
+  , jfiInternalVarExpr :: [JSONPathElement]
+  , jfiInternalVarType :: [JSONPathElement]
+  , jfiExternalVars    :: [JSONPathElement]
+  , jfiExternalVarId   :: [JSONPathElement]
+  , jfiExternalVarType :: [JSONPathElement]
+  , jfiRequirements    :: [JSONPathElement]
+  , jfiRequirementId   :: [JSONPathElement]
+  , jfiRequirementDesc :: [JSONPathElement]
+  , jfiRequirementExpr :: [JSONPathElement]
+  }
+
+parseJSONFormat :: JSONFormat -> Either String JSONFormatInternal
+parseJSONFormat jsonFormat = do
+  jfi2  <- showErrors $ parseJSONPath (pack (specInternalVars    jsonFormat))
+  jfi3  <- showErrors $ parseJSONPath (pack (specInternalVarId   jsonFormat))
+  jfi4  <- showErrors $ parseJSONPath (pack (specInternalVarExpr jsonFormat))
+  jfi5  <- showErrors $ parseJSONPath (pack (specInternalVarType jsonFormat))
+  jfi6  <- showErrors $ parseJSONPath (pack (specExternalVars    jsonFormat))
+  jfi7  <- showErrors $ parseJSONPath (pack (specExternalVarId   jsonFormat))
+  jfi8  <- showErrors $ parseJSONPath (pack (specExternalVarType jsonFormat))
+  jfi9  <- showErrors $ parseJSONPath (pack (specRequirements    jsonFormat))
+  jfi10 <- showErrors $ parseJSONPath (pack (specRequirementId   jsonFormat))
+  jfi11 <- showErrors $ parseJSONPath (pack (specRequirementDesc jsonFormat))
+  jfi12 <- showErrors $ parseJSONPath (pack (specRequirementExpr jsonFormat))
+  return $ JSONFormatInternal
+             { jfiInternalVars    = jfi2
+             , jfiInternalVarId   = jfi3
+             , jfiInternalVarExpr = jfi4
+             , jfiInternalVarType = jfi5
+             , jfiExternalVars    = jfi6
+             , jfiExternalVarId   = jfi7
+             , jfiExternalVarType = jfi8
+             , jfiRequirements    = jfi9
+             , jfiRequirementId   = jfi10
+             , jfiRequirementDesc = jfi11
+             , jfiRequirementExpr = jfi12
+             }
+
+parseJSONSpec :: (String -> Either String a) -> JSONFormat -> Value -> Either String (Spec a)
+parseJSONSpec parseExpr jsonFormat value = do
+  jsonFormatInternal <- parseJSONFormat jsonFormat
+
+  let values :: [Value]
+      values = executeJSONPath (jfiInternalVars jsonFormatInternal) value
+
+      internalVarDef :: Value -> Either String InternalVariableDef
+      internalVarDef value = do
+        let msg = "internal variable name"
+        varId   <- valueToString msg =<< (listToEither msg (executeJSONPath (jfiInternalVarId jsonFormatInternal) value))
+
+        let msg = "internal variable type"
+        varType <- valueToString msg =<< (listToEither msg (executeJSONPath (jfiInternalVarType jsonFormatInternal) value))
+
+        let msg = "internal variable expr"
+        varExpr <- valueToString msg =<< (listToEither msg (executeJSONPath (jfiInternalVarExpr jsonFormatInternal) value))
+
+        return $ InternalVariableDef
+                   { internalVariableName    = varId
+                   , internalVariableType    = varType
+                   , internalVariableExpr    = varExpr
+                   }
+
+  internalVariableDefs <- mapM internalVarDef values
+
+  let values :: [Value]
+      values = executeJSONPath (jfiExternalVars jsonFormatInternal) value
+
+      externalVarDef :: Value -> Either String ExternalVariableDef
+      externalVarDef value = do
+
+        let msg = "external variable name"
+        varId   <- valueToString msg =<< (listToEither msg (executeJSONPath (jfiExternalVarId jsonFormatInternal) value))
+
+        let msg = "external variable type"
+        varType <- valueToString msg =<< (listToEither msg (executeJSONPath (jfiExternalVarType jsonFormatInternal) value))
+
+        return $ ExternalVariableDef
+                   { externalVariableName    = varId
+                   , externalVariableType    = varType
+                   }
+
+  externalVariableDefs <- mapM externalVarDef values
+
+  let values :: [Value]
+      values = executeJSONPath (jfiRequirements jsonFormatInternal) value
+
+      -- requirementDef :: Value -> Either String (Requirement a)
+      requirementDef value = do
+        let msg = "Requirement name"
+        reqId <- valueToString msg =<< (listToEither msg (executeJSONPath (jfiRequirementId jsonFormatInternal) value))
+
+        let msg = "Requirement expression"
+        reqExpr <- valueToString msg =<< (listToEither msg (executeJSONPath (jfiRequirementExpr jsonFormatInternal) value))
+        reqExpr' <- parseExpr reqExpr
+
+        let msg = "Requirement description"
+        reqDesc <- valueToString msg =<< (listToEither msg (executeJSONPath (jfiRequirementDesc jsonFormatInternal) value))
+
+        return $ Requirement
+                   { requirementName        = reqId
+                   , requirementExpr        = reqExpr'
+                   , requirementDescription = reqDesc
+                   }
+
+  requirements <- mapM requirementDef values
+
+  return $ Spec internalVariableDefs externalVariableDefs requirements
+
+valueToString :: String -> Value -> Either String String
+valueToString msg (String x) = Right $ unpack x
+valueToString msg _          = Left $ "The JSON value provided for " ++ msg ++ " does not contain a string"
+
+listToEither :: String -> [a] -> Either String a
+listToEither _   [x] = Right x
+listToEither msg []  = Left $ "Failed to find a value for " ++ msg
+listToEither msg _   = Left $ "Unexpectedly found multiple values for " ++ msg
+
+-- | Parse a JSONPath expression, returning its element components.
+parseJSONPath :: T.Text -> Either String [JSONPathElement]
+parseJSONPath = first errorBundlePretty . parse (jsonPath eof) ""
+
+showErrors :: Show a => Either a b -> Either String b
+showErrors (Left s)  = Left (show s)
+showErrors (Right x) = Right x
