Repository: kurtosis-tech/kurtosis
Pull request #891 (2023-07-13 17:59:59)

feat: allow for relative imports from packages
## Description:
Allow for relative imports from packages

## Is this change user facing?
YES

cloudflare-pages[bot]: ## Deploying with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>9c046f5</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>&nbsp;✅&nbsp; Deploy successful!</td></tr>
<tr><td><strong>Preview URL:</strong></td><td>
<a href='https://a495f3be.kurtosis-docs.pages.dev'>https://a495f3be.kurtosis-docs.pages.dev</a>
</td></tr>
<tr><td><strong>Branch Preview URL:</strong></td><td>
<a href='https://gyani-relative.kurtosis-docs.pages.dev'>https://gyani-relative.kurtosis-docs.pages.dev</a>
</td></tr>
</table>

[View logs](https://dash.cloudflare.com/?to=/:account/pages/view/kurtosis/a495f3be-3dbd-4fa3-802e-eb946306c525)


Patch:
diff --git a/container-engine-lib/go.sum b/container-engine-lib/go.sum
index 2244e82fa..f0f995653 100644
--- a/container-engine-lib/go.sum
+++ b/container-engine-lib/go.sum
@@ -145,6 +145,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
@@ -153,6 +154,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
+golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -160,6 +162,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
+golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -170,14 +173,17 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
+golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
+golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
+golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -188,12 +194,16 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
+golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
+golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
+golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -205,6 +215,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
+golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -231,6 +242,7 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@@ -262,6 +274,7 @@ k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
 k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
 k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
 k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc=
+k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
 sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
diff --git a/contexts-config-store/go.sum b/contexts-config-store/go.sum
index a2abdb7d6..aa42fc1fa 100644
--- a/contexts-config-store/go.sum
+++ b/contexts-config-store/go.sum
@@ -33,11 +33,14 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
+golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/core/server/api_container/server/api_container_service.go b/core/server/api_container/server/api_container_service.go
index b2916616e..77d42f705 100644
--- a/core/server/api_container/server/api_container_service.go
+++ b/core/server/api_container/server/api_container_service.go
@@ -92,7 +92,7 @@ func (apicService ApiContainerService) RunStarlarkScript(args *kurtosis_core_rpc
 	dryRun := shared_utils.GetOrDefaultBool(args.DryRun, defaultStartosisDryRun)
 	mainFuncName := args.GetMainFunctionName()
 
-	apicService.runStarlark(parallelism, dryRun, startosis_constants.PackageIdPlaceholderForStandaloneScript, mainFuncName, serializedStarlarkScript, serializedParams, args.GetExperimentalFeatures(), stream)
+	apicService.runStarlark(parallelism, dryRun, startosis_constants.PackageIdPlaceholderForStandaloneScript, mainFuncName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, serializedStarlarkScript, serializedParams, args.GetExperimentalFeatures(), stream)
 	return nil
 }
 
@@ -138,6 +138,10 @@ func (apicService ApiContainerService) RunStarlarkPackage(args *kurtosis_core_rp
 	relativePathToMainFile := args.GetRelativePathToMainFile()
 	mainFuncName := args.GetMainFunctionName()
 
+	if relativePathToMainFile == "" {
+		relativePathToMainFile = startosis_constants.MainFileName
+	}
+
 	// TODO: remove this fork once everything uses the UploadStarlarkPackage endpoint prior to calling this
 	//  right now the TS SDK still uses the old deprecated behavior
 	var scriptWithRunFunction string
@@ -155,7 +159,8 @@ func (apicService ApiContainerService) RunStarlarkPackage(args *kurtosis_core_rp
 		}
 		return nil
 	}
-	apicService.runStarlark(parallelism, dryRun, packageId, mainFuncName, scriptWithRunFunction, serializedParams, args.ExperimentalFeatures, stream)
+
+	apicService.runStarlark(parallelism, dryRun, packageId, mainFuncName, relativePathToMainFile, scriptWithRunFunction, serializedParams, args.ExperimentalFeatures, stream)
 	return nil
 }
 
@@ -599,12 +604,7 @@ func (apicService ApiContainerService) runStarlarkPackageSetup(
 		return "", interpretationError
 	}
 
-	var pathToMainFile string
-	if relativePathToMainFile == "" {
-		pathToMainFile = path.Join(packageRootPathOnDisk, startosis_constants.MainFileName)
-	} else {
-		pathToMainFile = path.Join(packageRootPathOnDisk, relativePathToMainFile)
-	}
+	pathToMainFile := path.Join(packageRootPathOnDisk, relativePathToMainFile)
 
 	if _, err := os.Stat(pathToMainFile); err != nil {
 		return "", startosis_errors.WrapWithInterpretationError(err, "An error occurred while verifying that '%v' exists in the package '%v' at '%v'", startosis_constants.MainFileName, packageId, pathToMainFile)
@@ -623,12 +623,13 @@ func (apicService ApiContainerService) runStarlark(
 	dryRun bool,
 	packageId string,
 	mainFunctionName string,
+	relativePathToMainFile string,
 	serializedStarlark string,
 	serializedParams string,
 	experimentalFeatures []kurtosis_core_rpc_api_bindings.KurtosisFeatureFlag,
 	stream grpc.ServerStream,
 ) {
-	responseLineStream := apicService.startosisRunner.Run(stream.Context(), dryRun, parallelism, packageId, mainFunctionName, serializedStarlark, serializedParams, experimentalFeatures)
+	responseLineStream := apicService.startosisRunner.Run(stream.Context(), dryRun, parallelism, packageId, mainFunctionName, relativePathToMainFile, serializedStarlark, serializedParams, experimentalFeatures)
 	for {
 		select {
 		case <-stream.Context().Done():
diff --git a/core/server/api_container/server/startosis_engine/builtins/import_module/import_module.go b/core/server/api_container/server/startosis_engine/builtins/import_module/import_module.go
index bb268a61e..17e56c0ba 100644
--- a/core/server/api_container/server/startosis_engine/builtins/import_module/import_module.go
+++ b/core/server/api_container/server/startosis_engine/builtins/import_module/import_module.go
@@ -65,12 +65,16 @@ type importModuleCapabilities struct {
 	moduleGlobalCache      map[string]*startosis_packages.ModuleCacheEntry
 }
 
-func (builtin *importModuleCapabilities) Interpret(arguments *builtin_argument.ArgumentValuesSet) (starlark.Value, *startosis_errors.InterpretationError) {
+func (builtin *importModuleCapabilities) Interpret(locatorOfModuleInWhichThisBuiltInIsBeingCalled string, arguments *builtin_argument.ArgumentValuesSet) (starlark.Value, *startosis_errors.InterpretationError) {
 	moduleInPackageStarlarkStr, err := builtin_argument.ExtractArgumentValue[starlark.String](arguments, ModuleFileArgName)
 	if err != nil {
 		return nil, explicitInterpretationError(err)
 	}
 	moduleInPackage := moduleInPackageStarlarkStr.GoString()
+	moduleInPackage, relativePathParsingInterpretationErr := builtin.packageContentProvider.GetAbsoluteLocatorForRelativeModuleLocator(locatorOfModuleInWhichThisBuiltInIsBeingCalled, moduleInPackage)
+	if relativePathParsingInterpretationErr != nil {
+		return nil, relativePathParsingInterpretationErr
+	}
 
 	var loadInProgress *startosis_packages.ModuleCacheEntry
 	cacheEntry, found := builtin.moduleGlobalCache[moduleInPackage]
diff --git a/core/server/api_container/server/startosis_engine/builtins/read_file/read_file.go b/core/server/api_container/server/startosis_engine/builtins/read_file/read_file.go
index 4283e6860..9bb66f244 100644
--- a/core/server/api_container/server/startosis_engine/builtins/read_file/read_file.go
+++ b/core/server/api_container/server/startosis_engine/builtins/read_file/read_file.go
@@ -41,12 +41,17 @@ type readFileCapabilities struct {
 	packageContentProvider startosis_packages.PackageContentProvider
 }
 
-func (builtin *readFileCapabilities) Interpret(arguments *builtin_argument.ArgumentValuesSet) (starlark.Value, *startosis_errors.InterpretationError) {
+func (builtin *readFileCapabilities) Interpret(locatorOfModuleInWhichThisBuiltInIsBeingCalled string, arguments *builtin_argument.ArgumentValuesSet) (starlark.Value, *startosis_errors.InterpretationError) {
 	srcValue, err := builtin_argument.ExtractArgumentValue[starlark.String](arguments, SrcArgName)
 	if err != nil {
 		return nil, startosis_errors.WrapWithInterpretationError(err, "Unable to extract value for arg '%s'", srcValue)
 	}
-	packageContent, interpretationErr := builtin.packageContentProvider.GetModuleContents(srcValue.GoString())
+	fileToReadStr := srcValue.GoString()
+	fileToReadStr, relativePathParsingInterpretationErr := builtin.packageContentProvider.GetAbsoluteLocatorForRelativeModuleLocator(locatorOfModuleInWhichThisBuiltInIsBeingCalled, fileToReadStr)
+	if relativePathParsingInterpretationErr != nil {
+		return nil, relativePathParsingInterpretationErr
+	}
+	packageContent, interpretationErr := builtin.packageContentProvider.GetModuleContents(fileToReadStr)
 	if interpretationErr != nil {
 		return nil, interpretationErr
 	}
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper.go
index 36eea35d6..a522827d4 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper.go
@@ -22,7 +22,8 @@ func (builtin *KurtosisHelper) CreateBuiltin() func(thread *starlark.Thread, b *
 			return nil, interpretationErr
 		}
 		helperInternal := newKurtosisHelperInternal(wrappedBuiltin, builtin.Capabilities)
-		result, interpretationErr := helperInternal.interpret()
+		locatorOfModuleInWhichThisBuiltInIsBeingCalled := thread.Name
+		result, interpretationErr := helperInternal.interpret(locatorOfModuleInWhichThisBuiltInIsBeingCalled)
 		if interpretationErr != nil {
 			return nil, interpretationErr
 		}
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper_capabilities.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper_capabilities.go
index 62a82db7a..1d3b24b7d 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper_capabilities.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper_capabilities.go
@@ -7,5 +7,5 @@ import (
 )
 
 type KurtosisHelperCapabilities interface {
-	Interpret(arguments *builtin_argument.ArgumentValuesSet) (starlark.Value, *startosis_errors.InterpretationError)
+	Interpret(locatorOfModuleInWhichThisBuiltInIsBeingCalled string, arguments *builtin_argument.ArgumentValuesSet) (starlark.Value, *startosis_errors.InterpretationError)
 }
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper_internal.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper_internal.go
index 5a46b8981..0371fd6ed 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper_internal.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_helper/kurtosis_helper_internal.go
@@ -20,6 +20,6 @@ func newKurtosisHelperInternal(wrappedBuiltin *kurtosis_starlark_framework.Kurto
 	}
 }
 
-func (builtin *kurtosisHelperInternal) interpret() (starlark.Value, *startosis_errors.InterpretationError) {
-	return builtin.capabilities.Interpret(builtin.GetArguments())
+func (builtin *kurtosisHelperInternal) interpret(locatorOfModuleInWhichThisBuiltInIsBeingCalled string) (starlark.Value, *startosis_errors.InterpretationError) {
+	return builtin.capabilities.Interpret(locatorOfModuleInWhichThisBuiltInIsBeingCalled, builtin.GetArguments())
 }
diff --git a/core/server/api_container/server/startosis_engine/startosis_constants/startosis_constants.go b/core/server/api_container/server/startosis_engine/startosis_constants/startosis_constants.go
index 0ef874614..c6b41c2c9 100644
--- a/core/server/api_container/server/startosis_engine/startosis_constants/startosis_constants.go
+++ b/core/server/api_container/server/startosis_engine/startosis_constants/startosis_constants.go
@@ -8,5 +8,6 @@ const (
 
 	NoOutputObject = ""
 
-	PackageIdPlaceholderForStandaloneScript = "DEFAULT_PACKAGE_ID_FOR_SCRIPT"
+	PackageIdPlaceholderForStandaloneScript     = "DEFAULT_PACKAGE_ID_FOR_SCRIPT"
+	PlaceHolderMainFileForPlaceStandAloneScript = ""
 )
diff --git a/core/server/api_container/server/startosis_engine/startosis_interpreter.go b/core/server/api_container/server/startosis_engine/startosis_interpreter.go
index a0e5cc5d2..6473e3acd 100644
--- a/core/server/api_container/server/startosis_engine/startosis_interpreter.go
+++ b/core/server/api_container/server/startosis_engine/startosis_interpreter.go
@@ -22,6 +22,7 @@ import (
 	"go.starlark.net/starlarkjson"
 	"go.starlark.net/starlarkstruct"
 	"go.starlark.net/syntax"
+	"path"
 	"strings"
 	"sync"
 )
@@ -86,6 +87,7 @@ func (interpreter *StartosisInterpreter) InterpretAndOptimizePlan(
 	ctx context.Context,
 	packageId string,
 	mainFunctionName string,
+	relativePathtoMainFile string,
 	serializedStarlark string,
 	serializedJsonParams string,
 	currentEnclavePlan *instructions_plan.InstructionsPlan,
@@ -93,7 +95,7 @@ func (interpreter *StartosisInterpreter) InterpretAndOptimizePlan(
 
 	// run interpretation with no mask at all to generate the list of instructions as if the enclave was empty
 	emptyPlanInstructionsMask := resolver.NewInstructionsPlanMask(0)
-	naiveInstructionsPlanSerializedScriptOutput, naiveInstructionsPlan, interpretationErrorApi := interpreter.Interpret(ctx, packageId, mainFunctionName, serializedStarlark, serializedJsonParams, emptyPlanInstructionsMask)
+	naiveInstructionsPlanSerializedScriptOutput, naiveInstructionsPlan, interpretationErrorApi := interpreter.Interpret(ctx, packageId, mainFunctionName, relativePathtoMainFile, serializedStarlark, serializedJsonParams, emptyPlanInstructionsMask)
 	if interpretationErrorApi != nil {
 		return startosis_constants.NoOutputObject, nil, interpretationErrorApi
 	}
@@ -163,7 +165,7 @@ func (interpreter *StartosisInterpreter) InterpretAndOptimizePlan(
 		}
 
 		// Now that we have a potential plan mask, try running interpretation again using this plan mask
-		attemptSerializedScriptOutput, attemptInstructionsPlan, interpretationErrorApi := interpreter.Interpret(ctx, packageId, mainFunctionName, serializedStarlark, serializedJsonParams, potentialMask)
+		attemptSerializedScriptOutput, attemptInstructionsPlan, interpretationErrorApi := interpreter.Interpret(ctx, packageId, mainFunctionName, relativePathtoMainFile, serializedStarlark, serializedJsonParams, potentialMask)
 		if interpretationErrorApi != nil {
 			// Note: there's no real reason why this interpretation would fail with an error, given that the package
 			// has been interpreted once already (right above). But to be on the safe side, check the error
@@ -229,6 +231,7 @@ func (interpreter *StartosisInterpreter) Interpret(
 	_ context.Context,
 	packageId string,
 	mainFunctionName string,
+	relativePathtoMainFile string,
 	serializedStarlark string,
 	serializedJsonParams string,
 	instructionsPlanMask *resolver.InstructionsPlanMask,
@@ -237,7 +240,11 @@ func (interpreter *StartosisInterpreter) Interpret(
 	defer interpreter.mutex.Unlock()
 	newInstructionsPlan := instructions_plan.NewInstructionsPlan()
 	logrus.Debugf("Interpreting package '%v' with contents '%v' and params '%v'", packageId, serializedStarlark, serializedJsonParams)
-	globalVariables, interpretationErr := interpreter.interpretInternal(packageId, serializedStarlark, newInstructionsPlan)
+	moduleLocator := packageId
+	if packageId != startosis_constants.PackageIdPlaceholderForStandaloneScript {
+		moduleLocator = path.Join(moduleLocator, relativePathtoMainFile)
+	}
+	globalVariables, interpretationErr := interpreter.interpretInternal(moduleLocator, serializedStarlark, newInstructionsPlan)
 	if interpretationErr != nil {
 		return startosis_constants.NoOutputObject, nil, interpretationErr.ToAPIType()
 	}
@@ -323,17 +330,18 @@ func (interpreter *StartosisInterpreter) Interpret(
 	return startosis_constants.NoOutputObject, newInstructionsPlan, nil
 }
 
-func (interpreter *StartosisInterpreter) interpretInternal(packageId string, serializedStarlark string, instructionPlan *instructions_plan.InstructionsPlan) (starlark.StringDict, *startosis_errors.InterpretationError) {
+func (interpreter *StartosisInterpreter) interpretInternal(moduleLocator string, serializedStarlark string, instructionPlan *instructions_plan.InstructionsPlan) (starlark.StringDict, *startosis_errors.InterpretationError) {
 	// We spin up a new thread for every call to interpreterInternal such that the stacktrace provided by the Starlark
 	// Go interpreter is relative to each individual thread, and we don't keep accumulating stacktrace entries from the
 	// previous calls inside the same thread
-	thread := newStarlarkThread(packageId)
+	// The thread name is set to the locator of the module so that we can use it to resolve relative paths
+	thread := newStarlarkThread(moduleLocator)
 	predeclared, interpretationErr := interpreter.buildBindings(instructionPlan)
 	if interpretationErr != nil {
 		return nil, interpretationErr
 	}
 
-	globalVariables, err := starlark.ExecFile(thread, packageId, serializedStarlark, *predeclared)
+	globalVariables, err := starlark.ExecFile(thread, moduleLocator, serializedStarlark, *predeclared)
 	if err != nil {
 		return nil, generateInterpretationError(err)
 	}
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider.go b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider.go
index 6094a4ac1..f3f7c58a3 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/git_package_content_provider.go
@@ -195,6 +195,21 @@ func (provider *GitPackageContentProvider) StorePackageContents(packageId string
 	return packageAbsolutePathOnDisk, nil
 }
 
+func (provider *GitPackageContentProvider) GetAbsoluteLocatorForRelativeModuleLocator(parentModuleId string, maybeRelativeLocator string) (string, *startosis_errors.InterpretationError) {
+	// maybe it's not a relative url in which case we return the url
+	_, errorParsingUrl := parseGitURL(maybeRelativeLocator)
+	if errorParsingUrl == nil {
+		return maybeRelativeLocator, nil
+	}
+
+	parsedParentModuleId, errorParsingPackageId := parseGitURL(parentModuleId)
+	if errorParsingPackageId != nil {
+		return "", startosis_errors.NewInterpretationError("Parent package id '%v' isn't a valid locator; relative URLs don't work with standalone scripts", parentModuleId)
+	}
+
+	return parsedParentModuleId.getAbsoluteLocatorRelativeToThisURL(maybeRelativeLocator), nil
+}
+
 // atomicClone This first clones to a temporary directory and then moves it
 // TODO make this support versioning via tags, commit hashes or branches
 func (provider *GitPackageContentProvider) atomicClone(parsedURL *ParsedGitURL) *startosis_errors.InterpretationError {
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/parsed_git_url.go b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/parsed_git_url.go
index ed832ffc4..8f3e7e756 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/parsed_git_url.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/parsed_git_url.go
@@ -103,6 +103,11 @@ func parseGitURL(packageURL string) (*ParsedGitURL, *startosis_errors.Interpreta
 	return parsedGitURL, nil
 }
 
+func (parsedUrl *ParsedGitURL) getAbsoluteLocatorRelativeToThisURL(relativeUrl string) string {
+	absoluteUrl := path.Join(startosis_constants.GithubDomainPrefix, path.Dir(parsedUrl.relativeFilePath), relativeUrl)
+	return absoluteUrl
+}
+
 // cleanPath removes empty "" from the string slice
 func cleanPathAndSplit(urlPath string) []string {
 	cleanPath := path.Clean(urlPath)
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider.go b/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider.go
index 51b9ccf7b..96dc85d2d 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.14.1. DO NOT EDIT.
+// Code generated by mockery v2.22.1. DO NOT EDIT.
 
 package startosis_packages
 
@@ -25,13 +25,16 @@ func (_m *MockPackageContentProvider) ClonePackage(packageId string) (string, *s
 	ret := _m.Called(packageId)
 
 	var r0 string
+	var r1 *startosis_errors.InterpretationError
+	if rf, ok := ret.Get(0).(func(string) (string, *startosis_errors.InterpretationError)); ok {
+		return rf(packageId)
+	}
 	if rf, ok := ret.Get(0).(func(string) string); ok {
 		r0 = rf(packageId)
 	} else {
 		r0 = ret.Get(0).(string)
 	}
 
-	var r1 *startosis_errors.InterpretationError
 	if rf, ok := ret.Get(1).(func(string) *startosis_errors.InterpretationError); ok {
 		r1 = rf(packageId)
 	} else {
@@ -66,18 +69,81 @@ func (_c *MockPackageContentProvider_ClonePackage_Call) Return(_a0 string, _a1 *
 	return _c
 }
 
+func (_c *MockPackageContentProvider_ClonePackage_Call) RunAndReturn(run func(string) (string, *startosis_errors.InterpretationError)) *MockPackageContentProvider_ClonePackage_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// GetAbsoluteLocatorForRelativeModuleLocator provides a mock function with given fields: packageId, relativeOrAbsoluteModulePath
+func (_m *MockPackageContentProvider) GetAbsoluteLocatorForRelativeModuleLocator(packageId string, relativeOrAbsoluteModulePath string) (string, *startosis_errors.InterpretationError) {
+	ret := _m.Called(packageId, relativeOrAbsoluteModulePath)
+
+	var r0 string
+	var r1 *startosis_errors.InterpretationError
+	if rf, ok := ret.Get(0).(func(string, string) (string, *startosis_errors.InterpretationError)); ok {
+		return rf(packageId, relativeOrAbsoluteModulePath)
+	}
+	if rf, ok := ret.Get(0).(func(string, string) string); ok {
+		r0 = rf(packageId, relativeOrAbsoluteModulePath)
+	} else {
+		r0 = ret.Get(0).(string)
+	}
+
+	if rf, ok := ret.Get(1).(func(string, string) *startosis_errors.InterpretationError); ok {
+		r1 = rf(packageId, relativeOrAbsoluteModulePath)
+	} else {
+		if ret.Get(1) != nil {
+			r1 = ret.Get(1).(*startosis_errors.InterpretationError)
+		}
+	}
+
+	return r0, r1
+}
+
+// MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAbsoluteLocatorForRelativeModuleLocator'
+type MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call struct {
+	*mock.Call
+}
+
+// GetAbsoluteLocatorForRelativeModuleLocator is a helper method to define mock.On call
+//   - packageId string
+//   - relativeOrAbsoluteModulePath string
+func (_e *MockPackageContentProvider_Expecter) GetAbsoluteLocatorForRelativeModuleLocator(packageId interface{}, relativeOrAbsoluteModulePath interface{}) *MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call {
+	return &MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call{Call: _e.mock.On("GetAbsoluteLocatorForRelativeModuleLocator", packageId, relativeOrAbsoluteModulePath)}
+}
+
+func (_c *MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call) Run(run func(packageId string, relativeOrAbsoluteModulePath string)) *MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(string), args[1].(string))
+	})
+	return _c
+}
+
+func (_c *MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call) Return(_a0 string, _a1 *startosis_errors.InterpretationError) *MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call) RunAndReturn(run func(string, string) (string, *startosis_errors.InterpretationError)) *MockPackageContentProvider_GetAbsoluteLocatorForRelativeModuleLocator_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // GetModuleContents provides a mock function with given fields: fileInsidePackageUrl
 func (_m *MockPackageContentProvider) GetModuleContents(fileInsidePackageUrl string) (string, *startosis_errors.InterpretationError) {
 	ret := _m.Called(fileInsidePackageUrl)
 
 	var r0 string
+	var r1 *startosis_errors.InterpretationError
+	if rf, ok := ret.Get(0).(func(string) (string, *startosis_errors.InterpretationError)); ok {
+		return rf(fileInsidePackageUrl)
+	}
 	if rf, ok := ret.Get(0).(func(string) string); ok {
 		r0 = rf(fileInsidePackageUrl)
 	} else {
 		r0 = ret.Get(0).(string)
 	}
 
-	var r1 *startosis_errors.InterpretationError
 	if rf, ok := ret.Get(1).(func(string) *startosis_errors.InterpretationError); ok {
 		r1 = rf(fileInsidePackageUrl)
 	} else {
@@ -112,18 +178,26 @@ func (_c *MockPackageContentProvider_GetModuleContents_Call) Return(_a0 string,
 	return _c
 }
 
+func (_c *MockPackageContentProvider_GetModuleContents_Call) RunAndReturn(run func(string) (string, *startosis_errors.InterpretationError)) *MockPackageContentProvider_GetModuleContents_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // GetOnDiskAbsoluteFilePath provides a mock function with given fields: fileInsidePackageUrl
 func (_m *MockPackageContentProvider) GetOnDiskAbsoluteFilePath(fileInsidePackageUrl string) (string, *startosis_errors.InterpretationError) {
 	ret := _m.Called(fileInsidePackageUrl)
 
 	var r0 string
+	var r1 *startosis_errors.InterpretationError
+	if rf, ok := ret.Get(0).(func(string) (string, *startosis_errors.InterpretationError)); ok {
+		return rf(fileInsidePackageUrl)
+	}
 	if rf, ok := ret.Get(0).(func(string) string); ok {
 		r0 = rf(fileInsidePackageUrl)
 	} else {
 		r0 = ret.Get(0).(string)
 	}
 
-	var r1 *startosis_errors.InterpretationError
 	if rf, ok := ret.Get(1).(func(string) *startosis_errors.InterpretationError); ok {
 		r1 = rf(fileInsidePackageUrl)
 	} else {
@@ -158,18 +232,26 @@ func (_c *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call) Return(_a0
 	return _c
 }
 
-// GetOnDiskAbsolutePath provides a mock function with given fields: packageId
+func (_c *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call) RunAndReturn(run func(string) (string, *startosis_errors.InterpretationError)) *MockPackageContentProvider_GetOnDiskAbsoluteFilePath_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// GetOnDiskAbsolutePackagePath provides a mock function with given fields: packageId
 func (_m *MockPackageContentProvider) GetOnDiskAbsolutePackagePath(packageId string) (string, *startosis_errors.InterpretationError) {
 	ret := _m.Called(packageId)
 
 	var r0 string
+	var r1 *startosis_errors.InterpretationError
+	if rf, ok := ret.Get(0).(func(string) (string, *startosis_errors.InterpretationError)); ok {
+		return rf(packageId)
+	}
 	if rf, ok := ret.Get(0).(func(string) string); ok {
 		r0 = rf(packageId)
 	} else {
 		r0 = ret.Get(0).(string)
 	}
 
-	var r1 *startosis_errors.InterpretationError
 	if rf, ok := ret.Get(1).(func(string) *startosis_errors.InterpretationError); ok {
 		r1 = rf(packageId)
 	} else {
@@ -181,41 +263,49 @@ func (_m *MockPackageContentProvider) GetOnDiskAbsolutePackagePath(packageId str
 	return r0, r1
 }
 
-// MockPackageContentProvider_GetOnDiskAbsolutePath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOnDiskAbsolutePackagePath'
-type MockPackageContentProvider_GetOnDiskAbsolutePath_Call struct {
+// MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOnDiskAbsolutePackagePath'
+type MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call struct {
 	*mock.Call
 }
 
-// GetOnDiskAbsolutePath is a helper method to define mock.On call
+// GetOnDiskAbsolutePackagePath is a helper method to define mock.On call
 //   - packageId string
-func (_e *MockPackageContentProvider_Expecter) GetOnDiskAbsolutePath(packageId interface{}) *MockPackageContentProvider_GetOnDiskAbsolutePath_Call {
-	return &MockPackageContentProvider_GetOnDiskAbsolutePath_Call{Call: _e.mock.On("GetOnDiskAbsolutePackagePath", packageId)}
+func (_e *MockPackageContentProvider_Expecter) GetOnDiskAbsolutePackagePath(packageId interface{}) *MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call {
+	return &MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call{Call: _e.mock.On("GetOnDiskAbsolutePackagePath", packageId)}
 }
 
-func (_c *MockPackageContentProvider_GetOnDiskAbsolutePath_Call) Run(run func(packageId string)) *MockPackageContentProvider_GetOnDiskAbsolutePath_Call {
+func (_c *MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call) Run(run func(packageId string)) *MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(string))
 	})
 	return _c
 }
 
-func (_c *MockPackageContentProvider_GetOnDiskAbsolutePath_Call) Return(_a0 string, _a1 *startosis_errors.InterpretationError) *MockPackageContentProvider_GetOnDiskAbsolutePath_Call {
+func (_c *MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call) Return(_a0 string, _a1 *startosis_errors.InterpretationError) *MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call {
 	_c.Call.Return(_a0, _a1)
 	return _c
 }
 
+func (_c *MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call) RunAndReturn(run func(string) (string, *startosis_errors.InterpretationError)) *MockPackageContentProvider_GetOnDiskAbsolutePackagePath_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // StorePackageContents provides a mock function with given fields: packageId, packageContent, overwriteExisting
 func (_m *MockPackageContentProvider) StorePackageContents(packageId string, packageContent []byte, overwriteExisting bool) (string, *startosis_errors.InterpretationError) {
 	ret := _m.Called(packageId, packageContent, overwriteExisting)
 
 	var r0 string
+	var r1 *startosis_errors.InterpretationError
+	if rf, ok := ret.Get(0).(func(string, []byte, bool) (string, *startosis_errors.InterpretationError)); ok {
+		return rf(packageId, packageContent, overwriteExisting)
+	}
 	if rf, ok := ret.Get(0).(func(string, []byte, bool) string); ok {
 		r0 = rf(packageId, packageContent, overwriteExisting)
 	} else {
 		r0 = ret.Get(0).(string)
 	}
 
-	var r1 *startosis_errors.InterpretationError
 	if rf, ok := ret.Get(1).(func(string, []byte, bool) *startosis_errors.InterpretationError); ok {
 		r1 = rf(packageId, packageContent, overwriteExisting)
 	} else {
@@ -252,6 +342,11 @@ func (_c *MockPackageContentProvider_StorePackageContents_Call) Return(_a0 strin
 	return _c
 }
 
+func (_c *MockPackageContentProvider_StorePackageContents_Call) RunAndReturn(run func(string, []byte, bool) (string, *startosis_errors.InterpretationError)) *MockPackageContentProvider_StorePackageContents_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 type mockConstructorTestingTNewMockPackageContentProvider interface {
 	mock.TestingT
 	Cleanup(func())
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider/mock_package_content_provider.go b/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider/mock_package_content_provider.go
index 18f6877f1..8731154d8 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider/mock_package_content_provider.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/mock_package_content_provider/mock_package_content_provider.go
@@ -1,9 +1,11 @@
 package mock_package_content_provider
 
 import (
+	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/startosis_constants"
 	"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/startosis_errors"
 	"github.com/kurtosis-tech/stacktrace"
 	"os"
+	"strings"
 )
 
 const (
@@ -62,6 +64,14 @@ func (provider *MockPackageContentProvider) GetModuleContents(fileInsidePackageU
 	return string(fileContent), nil
 }
 
+func (provider *MockPackageContentProvider) GetAbsoluteLocatorForRelativeModuleLocator(_ string, relativeOrAbsoluteModulePath string) (string, *startosis_errors.InterpretationError) {
+	if strings.HasPrefix(relativeOrAbsoluteModulePath, startosis_constants.GithubDomainPrefix) {
+		return relativeOrAbsoluteModulePath, nil
+	}
+	// TODO implement properly so that it works with relative paths
+	return "", nil
+}
+
 func (provider *MockPackageContentProvider) AddFileContent(packageId string, contents string) error {
 	absFilePath, err := writeContentToTempFile(contents)
 	if err != nil {
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/package_content_provider.go b/core/server/api_container/server/startosis_engine/startosis_packages/package_content_provider.go
index 3cf558599..0e60a9fa6 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/package_content_provider.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/package_content_provider.go
@@ -21,4 +21,7 @@ type PackageContentProvider interface {
 
 	// ClonePackage clones the package with the given id and returns the absolute path on disk
 	ClonePackage(packageId string) (string, *startosis_errors.InterpretationError)
+
+	// GetAbsoluteLocatorForRelativeModuleLocator returns the absolute package path for a relative module path
+	GetAbsoluteLocatorForRelativeModuleLocator(packageId string, relativeOrAbsoluteModulePath string) (string, *startosis_errors.InterpretationError)
 }
diff --git a/core/server/api_container/server/startosis_engine/startosis_runner.go b/core/server/api_container/server/startosis_engine/startosis_runner.go
index 4fb37a66d..2119033b1 100644
--- a/core/server/api_container/server/startosis_engine/startosis_runner.go
+++ b/core/server/api_container/server/startosis_engine/startosis_runner.go
@@ -48,6 +48,7 @@ func (runner *StartosisRunner) Run(
 	parallelism int,
 	packageId string,
 	mainFunctionName string,
+	relativePathToMainFile string,
 	serializedStartosis string,
 	serializedParams string,
 	experimentalFeatures []kurtosis_core_rpc_api_bindings.KurtosisFeatureFlag,
@@ -99,6 +100,7 @@ func (runner *StartosisRunner) Run(
 				ctx,
 				packageId,
 				mainFunctionName,
+				relativePathToMainFile,
 				serializedStartosis,
 				serializedParams,
 				resolver.NewInstructionsPlanMask(0),
@@ -108,6 +110,7 @@ func (runner *StartosisRunner) Run(
 				ctx,
 				packageId,
 				mainFunctionName,
+				relativePathToMainFile,
 				serializedStartosis,
 				serializedParams,
 				runner.startosisExecutor.enclavePlan,
diff --git a/docs/docs/concepts-reference/locators.md b/docs/docs/concepts-reference/locators.md
index fe97d222f..e39a4b005 100644
--- a/docs/docs/concepts-reference/locators.md
+++ b/docs/docs/concepts-reference/locators.md
@@ -36,11 +36,38 @@ github.com/kurtosis-tech/kurtosis/starlark/test.star
 Only locators pointing to public GitHub repositories are currently allowed.
 :::
 
+Relative Locators are supported but the relative locator needs to be inside the package. Relative locators are relative to the file being interpreted. For a Starlark script to reference a local file (i.e. one that lives next to in the filesystem), the Starlark script must use the name of the package that it lives inside.
+
+For example, suppose we had a [Kurtosis package][packages] like so:
+
+```
+/
+    package-repo
+        main.star
+        src/
+            lib.star
+```
+
+with a `kurtosis.yml` file like so:
+
+```yaml
+name: github.com/package-author/package-repo
+```
+
+The `main.star` can refer to the `lib.star` in both of the following ways
+
+
+```
+# valid relative import
+lib_via_relative_import = import_module("./src/lib.star")
+
+# valid absolute import
+lib_via_absolute_import = import_module("github.com/kurtosis-tech/package-repo/src/lib.star")
+```
+
 Any Starlark script that wishes to use external resources must be
 a part of a [Kurtosis package][packages].
 
-All locators are absolute; "relative" locators do not exist. For a Starlark script to reference a local file (i.e. one that lives next to in the filesystem), the Starlark script must use the name of the package that it lives inside.
-
 For example, suppose we had a [Kurtosis package][packages] like so:
 
 ```
diff --git a/grpc-file-transfer/golang/go.sum b/grpc-file-transfer/golang/go.sum
index c8ce6c288..03bc540a6 100644
--- a/grpc-file-transfer/golang/go.sum
+++ b/grpc-file-transfer/golang/go.sum
@@ -28,16 +28,23 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
+golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
+golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
+golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 h1:2FZP5XuJY9zQyGM5N0rtovnoXjiMUEIUMvw0m9wlpLc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o=
 google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
+google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=


Test patch:
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/import_module_framework_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/import_module_framework_test.go
index cf322f85c..8805029c0 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/import_module_framework_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/import_module_framework_test.go
@@ -50,6 +50,7 @@ func (t *importModuleTestCase) GetId() string {
 func (t *importModuleTestCase) GetHelper() *kurtosis_helper.KurtosisHelper {
 	packageContentProvider := startosis_packages.NewMockPackageContentProvider(t)
 	packageContentProvider.EXPECT().GetModuleContents(TestModuleFileName).Return("Hello World!", nil)
+	packageContentProvider.EXPECT().GetAbsoluteLocatorForRelativeModuleLocator(frameworkTestThreadName, TestModuleFileName).Return(TestModuleFileName, nil)
 
 	recursiveInterpret := func(moduleId string, scriptContent string) (starlark.StringDict, *startosis_errors.InterpretationError) {
 		return importModule_mockStarlarkModule.Members, nil
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/read_file_framework_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/read_file_framework_test.go
index d7e0e9eb3..fa94668e1 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/read_file_framework_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/read_file_framework_test.go
@@ -18,6 +18,7 @@ type readFileTestCase struct {
 
 func newReadFileTestCase(t *testing.T) *readFileTestCase {
 	packageContentProvider := startosis_packages.NewMockPackageContentProvider(t)
+	packageContentProvider.EXPECT().GetAbsoluteLocatorForRelativeModuleLocator(frameworkTestThreadName, TestModuleFileName).Return(TestModuleFileName, nil)
 	packageContentProvider.EXPECT().GetModuleContents(TestModuleFileName).Return("Hello World!", nil)
 	return &readFileTestCase{
 		T:                      t,
@@ -42,6 +43,7 @@ func (t *readFileTestCase) GetStarlarkCodeForAssertion() string {
 }
 
 func (t *readFileTestCase) Assert(result starlark.Value) {
+	t.packageContentProvider.AssertCalled(t, "GetAbsoluteLocatorForRelativeModuleLocator", frameworkTestThreadName, TestModuleFileName)
 	t.packageContentProvider.AssertCalled(t, "GetModuleContents", TestModuleFileName)
 	require.Equal(t, result, starlark.String("Hello World!"))
 }
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/starlark_framework_engine_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/starlark_framework_engine_test.go
index da7c1ac11..5c0e67663 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/starlark_framework_engine_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/starlark_framework_engine_test.go
@@ -20,7 +20,8 @@ import (
 )
 
 const (
-	resultStarlarkVar = "result"
+	resultStarlarkVar       = "result"
+	frameworkTestThreadName = "framework-testing-engine"
 )
 
 func TestAllRegisteredBuiltins(t *testing.T) {
@@ -75,7 +76,7 @@ func TestAllRegisteredBuiltins(t *testing.T) {
 func testKurtosisPlanInstruction(t *testing.T, builtin KurtosisPlanInstructionBaseTest) {
 	testId := builtin.GetId()
 	instructionsPlan := instructions_plan.NewInstructionsPlan()
-	thread := newStarlarkThread("framework-testing-engine")
+	thread := newStarlarkThread(frameworkTestThreadName)
 
 	predeclared := getBasePredeclaredDict(t)
 	// Add the KurtosisPlanInstruction that is being tested
diff --git a/core/server/api_container/server/startosis_engine/startosis_interpreter_idempotent_test.go b/core/server/api_container/server/startosis_engine/startosis_interpreter_idempotent_test.go
index a55ab8284..e780f8748 100644
--- a/core/server/api_container/server/startosis_engine/startosis_interpreter_idempotent_test.go
+++ b/core/server/api_container/server/startosis_engine/startosis_interpreter_idempotent_test.go
@@ -50,6 +50,7 @@ def run(plan, args):
 		context.Background(),
 		startosis_constants.PackageIdPlaceholderForStandaloneScript,
 		useDefaultMainFunctionName,
+		startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript,
 		script,
 		noInputParams,
 		currentEnclavePlan,
@@ -106,6 +107,7 @@ def run(plan, args):
 		context.Background(),
 		startosis_constants.PackageIdPlaceholderForStandaloneScript,
 		useDefaultMainFunctionName,
+		startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript,
 		script,
 		noInputParams,
 		currentEnclavePlan,
@@ -160,6 +162,7 @@ def run(plan, args):
 		context.Background(),
 		startosis_constants.PackageIdPlaceholderForStandaloneScript,
 		useDefaultMainFunctionName,
+		startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript,
 		script,
 		noInputParams,
 		currentEnclavePlan,
@@ -218,6 +221,7 @@ def run(plan, args):
 		context.Background(),
 		startosis_constants.PackageIdPlaceholderForStandaloneScript,
 		useDefaultMainFunctionName,
+		startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript,
 		script,
 		noInputParams,
 		currentEnclavePlan,
@@ -278,6 +282,7 @@ def run(plan, args):
 		context.Background(),
 		startosis_constants.PackageIdPlaceholderForStandaloneScript,
 		useDefaultMainFunctionName,
+		startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript,
 		script,
 		noInputParams,
 		currentEnclavePlan,
diff --git a/core/server/api_container/server/startosis_engine/startosis_interpreter_test.go b/core/server/api_container/server/startosis_engine/startosis_interpreter_test.go
index cbccae8a6..e024921b7 100644
--- a/core/server/api_container/server/startosis_engine/startosis_interpreter_test.go
+++ b/core/server/api_container/server/startosis_engine/startosis_interpreter_test.go
@@ -54,7 +54,7 @@ def run(plan):
 	plan.print("` + testString + `")
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 1, instructionsPlan.Size()) // Only the print statement
 
@@ -81,7 +81,7 @@ def deploy_contract(plan,service_name,contract_name,init_message,args):
 	mainFunctionName := "deploy_contract"
 	inputArgs := `{"service_name": "my-service", "contract_name": "my-contract", "init_message": "Init message", "args": {"arg1": "arg1-value", "arg2": "arg2-value"}}`
 
-	result, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, mainFunctionName, script, inputArgs, emptyInstructionsPlanMask)
+	result, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, mainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, inputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 3, instructionsPlan.Size()) // The three print functions
 	require.NotNil(t, result)
@@ -108,7 +108,7 @@ def my_func(my_arg1, my_arg2, args):
 	mainFunctionName := "my_func"
 	inputArgs := `{"my_arg1": "foo", "my_arg2": "bar", "args": {"arg1": "arg1-value", "arg2": "arg2-value"}}`
 
-	result, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, mainFunctionName, script, inputArgs, emptyInstructionsPlanMask)
+	result, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, mainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, inputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 0, instructionsPlan.Size()) // There are no instructions to execute
 	require.NotNil(t, result)
@@ -130,7 +130,7 @@ def run(plan):
 	plan.print(my_dict)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 2, instructionsPlan.Size())
 
@@ -152,7 +152,7 @@ def run(plan):
 unknownInstruction()
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 
 	expectedError := startosis_errors.NewInterpretationErrorWithCustomMsg(
 		[]startosis_errors.CallFrame{
@@ -177,7 +177,7 @@ unknownVariable
 unknownInstruction2()
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 
 	expectedError := startosis_errors.NewInterpretationErrorWithCustomMsg(
 		[]startosis_errors.CallFrame{
@@ -203,7 +203,7 @@ def run():
 load("otherScript.start") # fails b/c load takes in at least 2 args
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 
 	expectedError := startosis_errors.NewInterpretationErrorFromStacktrace(
 		[]startosis_errors.CallFrame{
@@ -239,7 +239,7 @@ def run(plan):
 	plan.print("The grpc transport protocol is " + datastore_service.ports["grpc"].transport_protocol)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, fmt.Sprintf(script, testServiceName), startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, fmt.Sprintf(script, testServiceName), startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 5, instructionsPlan.Size())
 
@@ -278,7 +278,7 @@ def run(plan):
 	plan.print("The transport protocol is " + datastore_service.ports["grpc"].transport_protocol)
 	plan.print("The application protocol is " + datastore_service.ports["grpc"].application_protocol)
 `
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, fmt.Sprintf(script, testServiceName), startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, fmt.Sprintf(script, testServiceName), startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 6, instructionsPlan.Size())
 
@@ -312,7 +312,7 @@ def run(plan):
 	plan.add_service(name = service_name, config = config)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 
 	expectedError := startosis_errors.NewInterpretationErrorWithCauseAndCustomMsg(
 		errors.New("ServiceConfig: missing argument for image"),
@@ -347,7 +347,7 @@ def run(plan):
 	plan.add_service(name = service_name, config = config)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	expectedError := startosis_errors.NewInterpretationErrorWithCauseAndCustomMsg(
 		startosis_errors.NewInterpretationError(`The following argument(s) could not be parsed or did not pass validation: {"transport_protocol":"Invalid argument value for 'transport_protocol': 'TCPK'. Valid values are TCP, SCTP, UDP"}`),
 		[]startosis_errors.CallFrame{
@@ -381,7 +381,7 @@ def run(plan):
 	plan.add_service(name = service_name, config = config)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	expectedError := startosis_errors.NewInterpretationErrorWithCauseAndCustomMsg(
 		startosis_errors.NewInterpretationError(`The following argument(s) could not be parsed or did not pass validation: {"number":"Value for 'number' was expected to be an integer between 1 and 65535, but it was 'starlark.String'"}`),
 		[]startosis_errors.CallFrame{
@@ -425,7 +425,7 @@ def run(plan):
 	plan.print("Done!")
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 8, instructionsPlan.Size())
 
@@ -457,7 +457,7 @@ load("` + barModulePath + `", "a")
 def run(plan):
 	plan.print("Hello " + a)
 `
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	expectedError := startosis_errors.NewInterpretationErrorWithCustomMsg(
 		[]startosis_errors.CallFrame{
 			*startosis_errors.NewCallFrame("<toplevel>", startosis_errors.NewScriptPosition(startosis_constants.PackageIdPlaceholderForStandaloneScript, 2, 1)),
@@ -484,7 +484,7 @@ my_module = import_module("` + barModulePath + `")
 def run(plan):
 	plan.print("Hello " + my_module.a)
 `
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 1, instructionsPlan.Size()) // Only the print statement
 
@@ -495,7 +495,7 @@ def run(plan):
 
 func TestStartosisInterpreter_TransitiveLoading(t *testing.T) {
 	seedModules := make(map[string]string)
-	moduleBar := "github.com/foo/bar/lib.star"
+	moduleBar := "github.com/foo/doo/crib.star"
 	seedModules[moduleBar] = `a="World!"`
 	moduleDooWhichLoadsModuleBar := "github.com/foo/doo/lib.star"
 	seedModules[moduleDooWhichLoadsModuleBar] = `module_bar = import_module("` + moduleBar + `")
@@ -513,7 +513,7 @@ def run(plan):
 
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 1, instructionsPlan.Size())
 
@@ -541,7 +541,7 @@ def run(plan):
 	plan.print(module_doo.b)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	expectedError := startosis_errors.NewInterpretationErrorWithCustomMsg(
 		[]startosis_errors.CallFrame{
 			*startosis_errors.NewCallFrame("<toplevel>", startosis_errors.NewScriptPosition(moduleBarLoadsModuleDoo, 1, 27)),
@@ -566,7 +566,7 @@ def run(plan):
 	plan.print(my_module.b)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 
 	errorMsg := `Evaluation error: An error occurred while loading the module '` + nonExistentModule + `'
 	Caused by: Package '` + nonExistentModule + `' not found`
@@ -593,7 +593,7 @@ def run(plan):
 `
 
 	// assert that first load fails
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.NotNil(t, interpretationError)
 	require.Nil(t, instructionsPlan)
 
@@ -602,7 +602,7 @@ def run(plan):
 	expectedOutput := `Hello World!
 `
 	// assert that second load succeeds
-	_, instructionsPlan, interpretationError = interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError = interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 1, instructionsPlan.Size())
 	validateScriptOutputFromPrintInstructions(t, instructionsPlan, expectedOutput)
@@ -633,7 +633,7 @@ def run(plan):
 	plan.add_service(name = module_bar.service_name, config = module_bar.config)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 3, instructionsPlan.Size())
 
@@ -681,7 +681,7 @@ def run(plan):
 	plan.print("Done!")
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 8, instructionsPlan.Size())
 
@@ -714,7 +714,7 @@ def run(plan):
 	plan.print("World!")
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 1, instructionsPlan.Size())
 
@@ -756,7 +756,7 @@ Adding service example-datastore-server
 Starting Startosis script!
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, scriptA, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, scriptA, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 4, instructionsPlan.Size())
 	assertInstructionTypeAndPosition(t, instructionsPlan, 2, add_service.AddServiceBuiltinName, moduleBar, 12, 18)
@@ -781,7 +781,7 @@ def run(plan):
 Adding service example-datastore-server
 `
 
-	_, instructionsPlan, interpretationError = interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, scriptB, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError = interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, scriptB, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 3, instructionsPlan.Size())
 	assertInstructionTypeAndPosition(t, instructionsPlan, 2, add_service.AddServiceBuiltinName, startosis_constants.PackageIdPlaceholderForStandaloneScript, 14, 18)
@@ -805,7 +805,7 @@ def run(plan):
 	plan.print(file_contents)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 2, instructionsPlan.Size())
 
@@ -843,7 +843,7 @@ def run(plan):
 	plan.print(artifact_name)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 3, instructionsPlan.Size())
 
@@ -889,7 +889,7 @@ def run(plan):
 	plan.print(uuid)
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 4, instructionsPlan.Size())
 
@@ -915,7 +915,7 @@ def run(plan):
 	plan.print("The service example-datastore-server has been removed")
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 3, instructionsPlan.Size())
 
@@ -937,7 +937,7 @@ func TestStartosisInterpreter_NoPanicIfUploadIsPassedAPathNotOnDisk(t *testing.T
 def run(plan):
 	plan.upload_files("` + filePath + `")
 `
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.NotNil(t, interpretationError)
 	require.Nil(t, instructionsPlan)
 }
@@ -952,7 +952,7 @@ def run(plan):
 	plan.print("Hello World!")
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 1, instructionsPlan.Size())
 
@@ -971,7 +971,7 @@ def run(plan):
 	plan.print("Hello World!")
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, `{"number": 4}`, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, `{"number": 4}`, emptyInstructionsPlanMask)
 	require.NotNil(t, interpretationError)
 	require.Nil(t, instructionsPlan)
 }
@@ -986,7 +986,7 @@ def run(plan, args):
 	plan.print("My favorite number is {0}".format(args["number"]))
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, `{"number": 4}`, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, `{"number": 4}`, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 1, instructionsPlan.Size())
 
@@ -1008,7 +1008,7 @@ def run(plan, args):
 		plan.print("Sorry no args!")
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 1, instructionsPlan.Size())
 
@@ -1027,7 +1027,7 @@ def run(plan, args, invalid_arg):
 	plan.print("this wouldn't interpret so the text here doesnt matter")
 `
 
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.NotNil(t, interpretationError)
 	expectedError := "Evaluation error: function run missing 2 arguments (args, invalid_arg)"
 	require.Contains(t, interpretationError.GetErrorMessage(), expectedError)
@@ -1045,7 +1045,7 @@ def run(plan, a, b):
 `
 	missingArgumentCount := 1
 	missingArgument := "b"
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, `{"a": "x"}`, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, `{"a": "x"}`, emptyInstructionsPlanMask)
 	require.NotNil(t, interpretationError)
 
 	expectedError := fmt.Sprintf("Evaluation error: function run missing %d argument (%v)", missingArgumentCount, missingArgument)
@@ -1062,7 +1062,7 @@ func TestStartosisInterpreter_RunWithUnpackedDict(t *testing.T) {
 def run(plan, a, b=1):
 	plan.print("My favorite number is {0}, but my favorite letter is {1}".format(b, a))
 `
-	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, `{"a": "x"}`, emptyInstructionsPlanMask)
+	_, instructionsPlan, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, `{"a": "x"}`, emptyInstructionsPlanMask)
 	require.Nil(t, interpretationError)
 	require.Equal(t, 1, instructionsPlan.Size())
 	expectedOutput := "My favorite number is 1, but my favorite letter is x\n"
@@ -1079,7 +1079,7 @@ def run(plan):
 	print("this doesnt matter")
 `
 
-	_, _, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
+	_, _, interpretationError := interpreter.Interpret(context.Background(), startosis_constants.PackageIdPlaceholderForStandaloneScript, useDefaultMainFunctionName, startosis_constants.PlaceHolderMainFileForPlaceStandAloneScript, script, startosis_constants.EmptyInputArgs, emptyInstructionsPlanMask)
 	require.NotNil(t, interpretationError)
 	require.Equal(t, fmt.Sprintf("Evaluation error: %v\n\tat [3:7]: run\n\tat [0:0]: print", print_builtin.UsePlanFromKurtosisInstructionError), interpretationError.GetErrorMessage())
 }
diff --git a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/parsed_git_url_test.go b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/parsed_git_url_test.go
index 1fd73ba82..f9a89fe53 100644
--- a/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/parsed_git_url_test.go
+++ b/core/server/api_container/server/startosis_engine/startosis_packages/git_package_content_provider/parsed_git_url_test.go
@@ -119,3 +119,20 @@ func TestParsedGitURL_WorksWithVersioningInformation(t *testing.T) {
 
 	require.Equal(t, expectedParsedURL, parsedURL)
 }
+
+func TestParsedGitUrl_ResolvesRelativeUrl(t *testing.T) {
+	parsedUrl, err := parseGitURL(githubSampleURL)
+	require.Nil(t, err)
+
+	relativeUrl := "./lib.star"
+	absoluteUrl := parsedUrl.getAbsoluteLocatorRelativeToThisURL(relativeUrl)
+	require.Nil(t, err)
+	expected := "github.com/kurtosis-tech/sample-startosis-load/lib.star"
+	require.Equal(t, expected, absoluteUrl)
+
+	relativeUrl = "./src/lib.star"
+	absoluteUrl = parsedUrl.getAbsoluteLocatorRelativeToThisURL(relativeUrl)
+	require.Nil(t, err)
+	expected = "github.com/kurtosis-tech/sample-startosis-load/src/lib.star"
+	require.Equal(t, expected, absoluteUrl)
+}
diff --git a/internal_testsuites/golang/testsuite/startosis_package_test/startosis_package_relative_import_test.go b/internal_testsuites/golang/testsuite/startosis_package_test/startosis_package_relative_import_test.go
new file mode 100644
index 000000000..53cadc32a
--- /dev/null
+++ b/internal_testsuites/golang/testsuite/startosis_package_test/startosis_package_relative_import_test.go
@@ -0,0 +1,22 @@
+package startosis_package_test
+
+import (
+	"context"
+	"github.com/stretchr/testify/require"
+)
+
+const (
+	packageWithRelativeImport = "../../../starlark/valid-package-with-relative-imports"
+)
+
+func (suite *StartosisPackageTestSuite) TestStartosisPackage_RelativeImports() {
+	ctx := context.Background()
+	runResult, _ := suite.RunPackage(ctx, packageWithRelativeImport)
+
+	t := suite.T()
+	require.Nil(t, runResult.InterpretationError)
+	require.Empty(t, runResult.ValidationErrors)
+	require.Nil(t, runResult.ExecutionError)
+	expectedResult := "John Doe\nOpen Sesame\n"
+	require.Equal(t, expectedResult, string(runResult.RunOutput))
+}
diff --git a/internal_testsuites/starlark/valid-package-with-relative-imports/kurtosis.yml b/internal_testsuites/starlark/valid-package-with-relative-imports/kurtosis.yml
new file mode 100644
index 000000000..4cba006ae
--- /dev/null
+++ b/internal_testsuites/starlark/valid-package-with-relative-imports/kurtosis.yml
@@ -0,0 +1,1 @@
+name: "github.com/sample/sample-kurtosis-package"
diff --git a/internal_testsuites/starlark/valid-package-with-relative-imports/main.star b/internal_testsuites/starlark/valid-package-with-relative-imports/main.star
new file mode 100644
index 000000000..db46176f0
--- /dev/null
+++ b/internal_testsuites/starlark/valid-package-with-relative-imports/main.star
@@ -0,0 +1,6 @@
+lib = import_module("./src/lib.star")
+password = read_file("./static_files/password.txt")
+
+def run(plan):
+    plan.print(lib.NAME)
+    plan.print(password)
diff --git a/internal_testsuites/starlark/valid-package-with-relative-imports/src/lib.star b/internal_testsuites/starlark/valid-package-with-relative-imports/src/lib.star
new file mode 100644
index 000000000..faf7a29e0
--- /dev/null
+++ b/internal_testsuites/starlark/valid-package-with-relative-imports/src/lib.star
@@ -0,0 +1,1 @@
+NAME = "John Doe"
diff --git a/internal_testsuites/starlark/valid-package-with-relative-imports/static_files/password.txt b/internal_testsuites/starlark/valid-package-with-relative-imports/static_files/password.txt
new file mode 100644
index 000000000..0e7b6c3ce
--- /dev/null
+++ b/internal_testsuites/starlark/valid-package-with-relative-imports/static_files/password.txt
@@ -0,0 +1,1 @@
+Open Sesame
\ No newline at end of file