diff --git a/core/commands2/refs.go b/core/commands2/refs.go
new file mode 100644
index 0000000000000000000000000000000000000000..f66746ff8cb6118d0f59aab04460c41822a48bb2
--- /dev/null
+++ b/core/commands2/refs.go
@@ -0,0 +1,132 @@
+package commands
+
+import (
+	"fmt"
+
+	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
+	cmds "github.com/jbenet/go-ipfs/commands"
+	"github.com/jbenet/go-ipfs/core"
+	"github.com/jbenet/go-ipfs/core/commands2/internal"
+	dag "github.com/jbenet/go-ipfs/merkledag"
+	u "github.com/jbenet/go-ipfs/util"
+)
+
+type RefsOutput struct {
+	Refs []string
+}
+
+var refsCmd = &cmds.Command{
+	Description: "Lists link hashes from an object",
+	Help: `Retrieves the object named by <ipfs-path> and displays the link
+    hashes it contains, with the following format:
+
+    <link base58 hash>`,
+
+	Arguments: []cmds.Argument{
+		cmds.Argument{"ipfs-path", cmds.ArgString, true, true,
+			"Path to the object(s) to list refs from"},
+	},
+	Options: []cmds.Option{
+		cmds.Option{[]string{"unique", "u"}, cmds.Bool,
+			"Omit duplicate refs from output"},
+		cmds.Option{[]string{"recursive", "r"}, cmds.Bool,
+			"Recursively list links of child nodes"},
+	},
+	Run: func(res cmds.Response, req cmds.Request) {
+		n := req.Context().Node
+
+		opt, found := req.Option("unique")
+		unique, ok := opt.(bool)
+		if !ok && found {
+			unique = false
+		}
+
+		opt, found = req.Option("recursive")
+		recursive, ok := opt.(bool)
+		if !ok && found {
+			recursive = false
+		}
+
+		paths, err := internal.CastToStrings(req.Arguments())
+		if err != nil {
+			res.SetError(err, cmds.ErrNormal)
+			return
+		}
+
+		output, err := getRefs(n, paths, unique, recursive)
+		if err != nil {
+			res.SetError(err, cmds.ErrNormal)
+			return
+		}
+
+		res.SetOutput(output)
+	},
+	Type: &RefsOutput{},
+	Marshallers: map[cmds.EncodingType]cmds.Marshaller{
+		cmds.Text: func(res cmds.Response) ([]byte, error) {
+			output := res.Output().(*RefsOutput)
+			s := ""
+			for _, ref := range output.Refs {
+				s += fmt.Sprintln(ref)
+			}
+			return []byte(s), nil
+		},
+	},
+}
+
+func getRefs(n *core.IpfsNode, paths []string, unique, recursive bool) (*RefsOutput, error) {
+	var refsSeen map[u.Key]bool
+	if unique {
+		refsSeen = make(map[u.Key]bool)
+	}
+
+	refs := make([]string, 0)
+
+	for _, path := range paths {
+		object, err := n.Resolver.ResolvePath(path)
+		if err != nil {
+			return nil, err
+		}
+
+		refs, err = addRefs(n, object, refs, refsSeen, recursive)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return &RefsOutput{refs}, nil
+}
+
+func addRefs(n *core.IpfsNode, object *dag.Node, refs []string, refsSeen map[u.Key]bool, recursive bool) ([]string, error) {
+	for _, link := range object.Links {
+		var found bool
+		found, refs = addRef(link.Hash, refs, refsSeen)
+
+		if recursive && !found {
+			child, err := n.DAG.Get(u.Key(link.Hash))
+			if err != nil {
+				return nil, fmt.Errorf("cannot retrieve %s (%s)", link.Hash.B58String(), err)
+			}
+
+			refs, err = addRefs(n, child, refs, refsSeen, recursive)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return refs, nil
+}
+
+func addRef(h mh.Multihash, refs []string, refsSeen map[u.Key]bool) (bool, []string) {
+	if refsSeen != nil {
+		_, found := refsSeen[u.Key(h)]
+		if found {
+			return true, refs
+		}
+		refsSeen[u.Key(h)] = true
+	}
+
+	refs = append(refs, h.B58String())
+	return false, refs
+}
diff --git a/core/commands2/root.go b/core/commands2/root.go
index e66c71cf69a1acf03d7f67d175f94b2f06ac9d52..29fb82a5767470420fa9ac427e26541ca5c2fd56 100644
--- a/core/commands2/root.go
+++ b/core/commands2/root.go
@@ -71,6 +71,7 @@ var rootSubcommands = map[string]*cmds.Command{
 	"block":     blockCmd,
 	"update":    updateCmd,
 	"object":    objectCmd,
+	"refs":      refsCmd,
 }
 
 func init() {