diff --git a/core/interfaces.go b/core/interfaces.go
new file mode 100644
index 0000000..84dcdea
--- /dev/null
+++ b/core/interfaces.go
@@ -0,0 +1,15 @@
+package core
+// UpdateParsers stores all the update parsers that packwiz can use. Add your own update systems to this map.
+var UpdateParsers map[string]UpdateParser = make(map[string]UpdateParser)
+
+// UpdateParser takes an unparsed interface{}, and returns an Updater for a mod file
+type UpdateParser interface {
+	ParseUpdate(interface{}) (Updater, error)
+}
+
+// Updater checks for and does updates on a mod
+type Updater interface {
+	// DoUpdate returns true if an update was done, false otherwise
+	DoUpdate(Mod) (bool, error)
+}
+
diff --git a/core/mod.go b/core/mod.go
index f9e6e87..9700bf3 100644
--- a/core/mod.go
+++ b/core/mod.go
@@ -1,5 +1,9 @@
 package core
-import "github.com/BurntSushi/toml"
+import (
+	"errors"
+
+	"github.com/BurntSushi/toml"
+)
 
 // Mod stores metadata about a mod. This is written to a TOML file for each mod.
 type Mod struct {
@@ -13,7 +17,7 @@ type Mod struct {
 		HashFormat string `toml:"hash-format"`
 		Hash       string `toml:"hash"`
 	} `toml:"download"`
-	Update map[string]toml.Primitive `toml:"update"`
+	Update map[string]interface{} `toml:"update"`
 }
 
 // The three possible values of Side (the side that the mod is on) are "server", "client", and "both".
@@ -23,6 +27,28 @@ const (
 	UniversalSide = "both"
 )
 
+// LoadMod attempts to load a mod file from a path
+func LoadMod(modFile string) (Mod, error) {
+	var mod Mod
+	if _, err := toml.DecodeFile(modFile, &mod); err != nil {
+		return Mod{}, err
+	}
+	// Horrible reflection library to convert to Updaters
+	for k, v := range mod.Update {
+		updateParser, ok := UpdateParsers[k]
+		if ok {
+			updater, err := updateParser.ParseUpdate(v)
+			if err != nil {
+				return mod, err
+			}
+			mod.Update[k] = updater
+		} else {
+			return mod, errors.New("Update plugin " + k + " not found!")
+		}
+	}
+	return mod, nil
+}
+
 func (m Mod) Write() {
 
 }
diff --git a/curseforge/curseforge.go b/curseforge/curseforge.go
index 698adf5..ef87b4d 100644
--- a/curseforge/curseforge.go
+++ b/curseforge/curseforge.go
@@ -1,9 +1,9 @@
 package curseforge
-
 import (
 	"fmt"
 
 	"github.com/comp500/packwiz/core"
+	"github.com/mitchellh/mapstructure"
 	"github.com/urfave/cli"
 )
 
@@ -11,9 +11,45 @@ func init() {
 	core.Commands = append(core.Commands, cli.Command{
 		Name:  "curseforge",
 		Usage: "Manage curseforge-based mods",
-		Action: func(c *cli.Context) error {
-			fmt.Println("Not implemented yet!")
-			return nil
-		},
+		Subcommands: []cli.Command{{
+			Name:    "install",
+			Usage:   "Install a mod from a curseforge URL, slug or ID",
+			Aliases: []string{"add", "get"},
+			Action: func(c *cli.Context) error {
+				return cmdInstall(core.FlagsFromContext(c), c.Args().Get(0))
+			},
+		}, {
+			Name:  "import",
+			Usage: "Import an installed curseforge modpack",
+			Action: func(c *cli.Context) error {
+				fmt.Println("Not implemented yet!")
+				return nil
+			},
+		}},
 	})
+	core.UpdateParsers["curseforge"] = cfUpdateParser{}
 }
+func cmdInstall(flags core.Flags, mod string) error {
+	if len(mod) == 0 {
+		return cli.NewExitError("You must specify a mod.", 1)
+	}
+	fmt.Println("Not implemented yet!")
+	return nil
+}
+
+type cfUpdateParser struct{}
+
+func (u cfUpdateParser) ParseUpdate(updateUnparsed interface{}) (core.Updater, error) {
+	var updater cfUpdater
+	err := mapstructure.Decode(updateUnparsed, &updater)
+	return updater, err
+}
+
+type cfUpdater struct {
+	ProjectID int `mapstructure:"project-id"`
+}
+
+func (u cfUpdater) DoUpdate(mod core.Mod) (bool, error) {
+	return false, nil
+}
+
diff --git a/go.mod b/go.mod
index 841b11d..2149658 100644
--- a/go.mod
+++ b/go.mod
@@ -2,5 +2,6 @@ module github.com/comp500/packwiz
 
 require (
 	github.com/BurntSushi/toml v0.3.1
+	github.com/mitchellh/mapstructure v1.1.2
 	github.com/urfave/cli v1.20.0
 )
diff --git a/go.sum b/go.sum
index ca07569..41f194e 100644
--- a/go.sum
+++ b/go.sum
@@ -1,4 +1,6 @@
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=