diff --git a/core/commands/cat.go b/core/commands/cat.go
index 3a4899746be6754e1127c3fdcc1ec6561d9b72fd..2132cb616bee5fbf05c8ce5dee33d778e26337f5 100644
--- a/core/commands/cat.go
+++ b/core/commands/cat.go
@@ -18,7 +18,7 @@ var CatCmd = &cmds.Command{
 	Helptext: cmds.HelpText{
 		Tagline: "Show IPFS object data",
 		ShortDescription: `
-Retrieves the object named by <ipfs-path> and outputs the data
+Retrieves the object named by <ipfs-or-ipns-path> and outputs the data
 it contains.
 `,
 	},
@@ -62,7 +62,7 @@ func cat(ctx context.Context, node *core.IpfsNode, paths []string) ([]io.Reader,
 	readers := make([]io.Reader, 0, len(paths))
 	length := uint64(0)
 	for _, fpath := range paths {
-		dagnode, err := node.Resolver.ResolvePath(path.Path(fpath))
+		dagnode, err := core.Resolve(node, path.Path(fpath))
 		if err != nil {
 			return nil, 0, err
 		}
diff --git a/core/commands/get.go b/core/commands/get.go
index f0d6bb7c0903fdf4b08c792a68026e8fadef8b39..74ad0fbaa7d4a0dba089418b460825196b8b67c9 100644
--- a/core/commands/get.go
+++ b/core/commands/get.go
@@ -24,7 +24,7 @@ var GetCmd = &cmds.Command{
 	Helptext: cmds.HelpText{
 		Tagline: "Download IPFS objects",
 		ShortDescription: `
-Retrieves the object named by <ipfs-path> and stores the data to disk.
+Retrieves the object named by <ipfs-or-ipns-path> and stores the data to disk.
 
 By default, the output will be stored at ./<ipfs-path>, but an alternate path
 can be specified with '--output=<path>' or '-o=<path>'.
@@ -166,5 +166,11 @@ func getCompressOptions(req cmds.Request) (int, error) {
 }
 
 func get(node *core.IpfsNode, p string, compression int) (io.Reader, error) {
-	return utar.NewReader(path.Path(p), node.DAG, node.Resolver, compression)
+	pathToResolve := path.Path(p)
+	dagnode, err := core.Resolve(node, pathToResolve)
+	if err != nil {
+		return nil, err
+	}
+
+	return utar.NewReader(pathToResolve, node.DAG, dagnode, compression)
 }
diff --git a/core/commands/ls.go b/core/commands/ls.go
index a251326a6a68cf59ca2f55d85e8f3a99903ea3b8..9917426e1f2c52c62195c3427f8cc08ef8712de5 100644
--- a/core/commands/ls.go
+++ b/core/commands/ls.go
@@ -10,9 +10,10 @@ import (
 	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
 
 	cmds "github.com/ipfs/go-ipfs/commands"
+	core "github.com/ipfs/go-ipfs/core"
 	merkledag "github.com/ipfs/go-ipfs/merkledag"
 	path "github.com/ipfs/go-ipfs/path"
-	"github.com/ipfs/go-ipfs/unixfs"
+	unixfs "github.com/ipfs/go-ipfs/unixfs"
 	unixfspb "github.com/ipfs/go-ipfs/unixfs/pb"
 )
 
@@ -35,7 +36,7 @@ var LsCmd = &cmds.Command{
 	Helptext: cmds.HelpText{
 		Tagline: "List links from an object.",
 		ShortDescription: `
-Retrieves the object named by <ipfs-path> and displays the links
+Retrieves the object named by <ipfs-or-ipns-path> and displays the links
 it contains, with the following format:
 
   <link base58 hash> <link size in bytes> <link name>
@@ -65,7 +66,7 @@ it contains, with the following format:
 
 		dagnodes := make([]*merkledag.Node, 0)
 		for _, fpath := range paths {
-			dagnode, err := node.Resolver.ResolvePath(path.Path(fpath))
+			dagnode, err := core.Resolve(node, path.Path(fpath))
 			if err != nil {
 				res.SetError(err, cmds.ErrNormal)
 				return
diff --git a/core/commands/object.go b/core/commands/object.go
index b45ee4667eeb1815a660a1649c312055a30ac645..e4400199b3973690583c3265a46ffada7cc52687 100644
--- a/core/commands/object.go
+++ b/core/commands/object.go
@@ -345,7 +345,7 @@ Data should be in the format specified by the --inputenc flag.
 
 // objectData takes a key string and writes out the raw bytes of that node (if there is one)
 func objectData(n *core.IpfsNode, fpath path.Path) (io.Reader, error) {
-	dagnode, err := n.Resolver.ResolvePath(fpath)
+	dagnode, err := core.Resolve(n, fpath)
 	if err != nil {
 		return nil, err
 	}
@@ -357,7 +357,7 @@ func objectData(n *core.IpfsNode, fpath path.Path) (io.Reader, error) {
 
 // objectLinks takes a key string and lists the links it points to
 func objectLinks(n *core.IpfsNode, fpath path.Path) (*Object, error) {
-	dagnode, err := n.Resolver.ResolvePath(fpath)
+	dagnode, err := core.Resolve(n, fpath)
 	if err != nil {
 		return nil, err
 	}
@@ -369,7 +369,7 @@ func objectLinks(n *core.IpfsNode, fpath path.Path) (*Object, error) {
 
 // objectGet takes a key string from args and a format option and serializes the dagnode to that format
 func objectGet(n *core.IpfsNode, fpath path.Path) (*dag.Node, error) {
-	dagnode, err := n.Resolver.ResolvePath(fpath)
+	dagnode, err := core.Resolve(n, fpath)
 	if err != nil {
 		return nil, err
 	}
diff --git a/core/commands/refs.go b/core/commands/refs.go
index 67436c6ffb76777e0a6ed63c5ed9ea0cfa0f3f67..f6df161537a74f82b69347e962dba3f3f8121566 100644
--- a/core/commands/refs.go
+++ b/core/commands/refs.go
@@ -164,7 +164,7 @@ Displays the hashes of all local objects.
 func objectsForPaths(n *core.IpfsNode, paths []string) ([]*dag.Node, error) {
 	objects := make([]*dag.Node, len(paths))
 	for i, p := range paths {
-		o, err := n.Resolver.ResolvePath(path.Path(p))
+		o, err := core.Resolve(n, path.Path(p))
 		if err != nil {
 			return nil, err
 		}
diff --git a/core/core.go b/core/core.go
index 0add895251487a1cdc7bc577a39e2c1ae814f101..ca7abf36e6375977567297f0c9655713b9cd4a6a 100644
--- a/core/core.go
+++ b/core/core.go
@@ -345,10 +345,6 @@ func (n *IpfsNode) OnlineMode() bool {
 	}
 }
 
-func (n *IpfsNode) Resolve(fpath string) (*merkledag.Node, error) {
-	return n.Resolver.ResolvePath(path.Path(fpath))
-}
-
 func (n *IpfsNode) Bootstrap(cfg BootstrapConfig) error {
 
 	// TODO what should return value be when in offlineMode?
diff --git a/core/corerepo/pinning.go b/core/corerepo/pinning.go
index 804ec746c6dc42c82234da9df697eb872a5e994d..81acba43e7d284dd34d17b7924eb40e1b49be52f 100644
--- a/core/corerepo/pinning.go
+++ b/core/corerepo/pinning.go
@@ -16,7 +16,7 @@ func Pin(n *core.IpfsNode, paths []string, recursive bool) ([]u.Key, error) {
 
 	dagnodes := make([]*merkledag.Node, 0)
 	for _, fpath := range paths {
-		dagnode, err := n.Resolver.ResolvePath(path.Path(fpath))
+		dagnode, err := core.Resolve(n, path.Path(fpath))
 		if err != nil {
 			return nil, fmt.Errorf("pin: %s", err)
 		}
@@ -51,7 +51,7 @@ func Unpin(n *core.IpfsNode, paths []string, recursive bool) ([]u.Key, error) {
 
 	dagnodes := make([]*merkledag.Node, 0)
 	for _, fpath := range paths {
-		dagnode, err := n.Resolver.ResolvePath(path.Path(fpath))
+		dagnode, err := core.Resolve(n, path.Path(fpath))
 		if err != nil {
 			return nil, err
 		}
diff --git a/core/pathresolver.go b/core/pathresolver.go
new file mode 100644
index 0000000000000000000000000000000000000000..c84821ce718a12485bef423be9edc8e9ebf5218c
--- /dev/null
+++ b/core/pathresolver.go
@@ -0,0 +1,40 @@
+package core
+
+import (
+	merkledag "github.com/ipfs/go-ipfs/merkledag"
+	path "github.com/ipfs/go-ipfs/path"
+	"strings"
+)
+
+// Resolves the given path by parsing out /ipns/ entries and then going
+// through the /ipfs/ entries and returning the final merkledage node.
+// Effectively enables /ipns/ in CLI commands.
+func Resolve(n *IpfsNode, p path.Path) (*merkledag.Node, error) {
+	strpath := string(p)
+
+	// for now, we only try to resolve ipns paths if
+	// they begin with "/ipns/". Otherwise, ambiguity
+	// emerges when resolving just a <hash>. Is it meant
+	// to be an ipfs or an ipns resolution?
+
+	if strings.HasPrefix(strpath, "/ipns/") {
+		// if it's an ipns path, try to resolve it.
+		// if we can't, we can give that error back to the user.
+		ipnsPath := p.Segments()[1]
+		extensions := p.Segments()[2:]
+		key, err := n.Namesys.Resolve(n.Context(), ipnsPath)
+		if err != nil {
+			return nil, err
+		}
+
+		pathHead := make([]string, 2)
+		pathHead[0] = "ipfs"
+		pathHead[1] = key.Pretty()
+
+		p = path.FromSegments(append(pathHead, extensions...)...)
+		//p = path.RebasePath(path.FromSegments(extensions...), basePath)
+	}
+
+	// ok, we have an ipfs path now (or what we'll treat as one)
+	return n.Resolver.ResolvePath(p)
+}
diff --git a/path/path.go b/path/path.go
index ea83cd12ceb118529164047c0ecab6e0e7094d9c..7820880c17216fafc6957c52fc35859ca8fb2eee 100644
--- a/path/path.go
+++ b/path/path.go
@@ -1,10 +1,9 @@
 package path
 
 import (
+	u "github.com/ipfs/go-ipfs/util"
 	"path"
 	"strings"
-
-	u "github.com/ipfs/go-ipfs/util"
 )
 
 // TODO: debate making this a private struct wrapped in a public interface
@@ -36,3 +35,7 @@ func (p Path) Segments() []string {
 func (p Path) String() string {
 	return string(p)
 }
+
+func FromSegments(seg ...string) Path {
+	return Path(strings.Join(seg, "/"))
+}
diff --git a/unixfs/tar/reader.go b/unixfs/tar/reader.go
index 9509b2d6dc645a4ecd27bdd73f7fda9ded7c0628..405a0eb187acf80e86ea1ac4fc3b661494ed6aa5 100644
--- a/unixfs/tar/reader.go
+++ b/unixfs/tar/reader.go
@@ -28,12 +28,11 @@ type Reader struct {
 	err        error
 }
 
-func NewReader(path path.Path, dag mdag.DAGService, resolver *path.Resolver, compression int) (*Reader, error) {
+func NewReader(path path.Path, dag mdag.DAGService, dagnode *mdag.Node, compression int) (*Reader, error) {
 
 	reader := &Reader{
 		signalChan: make(chan struct{}),
 		dag:        dag,
-		resolver:   resolver,
 	}
 
 	var err error
@@ -47,11 +46,6 @@ func NewReader(path path.Path, dag mdag.DAGService, resolver *path.Resolver, com
 		reader.writer = tar.NewWriter(&reader.buf)
 	}
 
-	dagnode, err := resolver.ResolvePath(path)
-	if err != nil {
-		return nil, err
-	}
-
 	// writeToBuf will write the data to the buffer, and will signal when there
 	// is new data to read
 	_, filename := gopath.Split(path.String())