diff --git a/core/commands2/id.go b/core/commands2/id.go
new file mode 100644
index 0000000000000000000000000000000000000000..3a0bd6a77be9be47de7055ec04a3a3c31e13087a
--- /dev/null
+++ b/core/commands2/id.go
@@ -0,0 +1,103 @@
+package commands
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"time"
+
+	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
+
+	b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
+
+	cmds "github.com/jbenet/go-ipfs/commands"
+	"github.com/jbenet/go-ipfs/peer"
+	kb "github.com/jbenet/go-ipfs/routing/kbucket"
+	u "github.com/jbenet/go-ipfs/util"
+)
+
+const offlineIdErrorMessage = `ID command fails when run without daemon, we are working 
+to fix this In the meantime, please run the daemon if you want to use 'ipfs id'`
+
+type IdOutput struct {
+	ID              string
+	PublicKey       string
+	Addresses       []string
+	AgentVersion    string
+	ProtocolVersion string
+}
+
+var idCmd = &cmds.Command{
+	Helptext: cmds.HelpText{
+		Tagline: "Show IPFS Node ID info",
+		ShortDescription: `
+Prints out information about the specified peer,
+if no peer is specified, prints out local peers info.
+`,
+	},
+	Arguments: nil,
+	Run: func(req cmds.Request) (interface{}, error) {
+		node, err := req.Context().GetNode()
+		if err != nil {
+			return nil, err
+		}
+
+		if len(req.Arguments()) == 0 {
+			return printPeer(node.Identity)
+		}
+
+		pid, ok := req.Arguments()[0].(string)
+		if !ok {
+			return nil, errors.New("Improperly formatted peer id")
+		}
+
+		id := peer.ID(b58.Decode(pid))
+		ctx, _ := context.WithTimeout(context.TODO(), time.Second*5)
+		p, err := node.Routing.FindPeer(ctx, id)
+		if err == kb.ErrLookupFailure {
+			return nil, errors.New(offlineIdErrorMessage)
+		}
+		if err != nil {
+			return nil, err
+		}
+		return printPeer(p)
+	},
+	Marshalers: cmds.MarshalerMap{
+		cmds.Text: func(res cmds.Response) ([]byte, error) {
+			val, ok := res.Output().(*IdOutput)
+			if !ok {
+				return nil, u.ErrCast()
+			}
+
+			return json.MarshalIndent(val, "", "\t")
+		},
+	},
+	Type: &IdOutput{},
+}
+
+func printPeer(p peer.Peer) (interface{}, error) {
+	if p == nil {
+		return nil, errors.New("Attempted to print nil peer!")
+	}
+	info := new(IdOutput)
+
+	info.ID = p.ID().String()
+	if p.PubKey() == nil {
+		return nil, errors.New(`peer publickey not populated on offline runs,
+please run the daemon to use ipfs id!`)
+	}
+	pkb, err := p.PubKey().Bytes()
+	if err != nil {
+		return nil, err
+	}
+	info.PublicKey = base64.StdEncoding.EncodeToString(pkb)
+	for _, a := range p.Addresses() {
+		info.Addresses = append(info.Addresses, a.String())
+	}
+
+	agent, protocol := p.GetVersions()
+	info.AgentVersion = agent
+	info.ProtocolVersion = protocol
+
+	return info, nil
+}
diff --git a/core/commands2/root.go b/core/commands2/root.go
index f71b759557aa1181fd5e6adb1f6b3b1eae608ebb..3e711092e63d2c3b9f35db836f8e76e4b289e54e 100644
--- a/core/commands2/root.go
+++ b/core/commands2/root.go
@@ -32,6 +32,7 @@ Tool commands:
     update        Download and apply go-ipfs updates
     version       Show ipfs version information
     commands      List all available commands
+    id            Show info about ipfs peers
 
 Advanced Commands:
 
@@ -77,6 +78,7 @@ var rootSubcommands = map[string]*cmds.Command{
 	"update":    UpdateCmd,
 	"object":    objectCmd,
 	"refs":      refsCmd,
+	"id":        idCmd,
 }
 
 func init() {
diff --git a/core/core.go b/core/core.go
index 716369826a108bfae9acc7f6ac904f669d0aa709..09014cd1108274283b735670eb642d78af802e10 100644
--- a/core/core.go
+++ b/core/core.go
@@ -18,6 +18,7 @@ import (
 	merkledag "github.com/jbenet/go-ipfs/merkledag"
 	namesys "github.com/jbenet/go-ipfs/namesys"
 	inet "github.com/jbenet/go-ipfs/net"
+	handshake "github.com/jbenet/go-ipfs/net/handshake"
 	mux "github.com/jbenet/go-ipfs/net/mux"
 	netservice "github.com/jbenet/go-ipfs/net/service"
 	path "github.com/jbenet/go-ipfs/path"
@@ -223,6 +224,8 @@ func initIdentity(cfg *config.Identity, peers peer.Peerstore, online bool) (peer
 		return nil, err
 	}
 
+	self.SetVersions(handshake.ClientVersion, handshake.IpfsVersion.String())
+
 	// when not online, don't need to parse private keys (yet)
 	if online {
 		skb, err := base64.StdEncoding.DecodeString(cfg.PrivKey)
diff --git a/net/handshake/handshake1.go b/net/handshake/handshake1.go
index 306c933908e9f5603f455dd7cc3490a90d720ba4..99f8e2ac741cc14b086897517da5b939d100e430 100644
--- a/net/handshake/handshake1.go
+++ b/net/handshake/handshake1.go
@@ -10,13 +10,13 @@ import (
 	semver "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
 )
 
-// ipfsVersion holds the current protocol version for a client running this code
-var ipfsVersion *semver.Version
-var clientVersion = "go-ipfs/" + config.CurrentVersionNumber
+// IpfsVersion holds the current protocol version for a client running this code
+var IpfsVersion *semver.Version
+var ClientVersion = "go-ipfs/" + config.CurrentVersionNumber
 
 func init() {
 	var err error
-	ipfsVersion, err = semver.NewVersion("0.0.1")
+	IpfsVersion, err = semver.NewVersion("0.0.1")
 	if err != nil {
 		panic(fmt.Errorf("invalid protocol version: %v", err))
 	}
@@ -24,7 +24,7 @@ func init() {
 
 // Handshake1Msg returns the current protocol version as a protobuf message
 func Handshake1Msg() *pb.Handshake1 {
-	return NewHandshake1(ipfsVersion.String(), clientVersion)
+	return NewHandshake1(IpfsVersion.String(), ClientVersion)
 }
 
 // ErrVersionMismatch is returned when two clients don't share a protocol version
diff --git a/peer/peer.go b/peer/peer.go
index f38a2df211d755809ebc6d4f4ecc56806a9981dc..32751e7b0221c37430a520de293603a4a3e107bc 100644
--- a/peer/peer.go
+++ b/peer/peer.go
@@ -99,6 +99,9 @@ type Peer interface {
 	GetType() Type
 	SetType(Type)
 
+	//Get/Set Agent and Protocol Versions
+	GetVersions() (agent, protocol string)
+	SetVersions(agent, protocol string)
 	// Update with the data of another peer instance
 	Update(Peer) error
 
@@ -137,6 +140,9 @@ type peer struct {
 	// within that package, map from ID to latency value.
 	latency time.Duration
 
+	protocolVersion string
+	agentVersion    string
+
 	// typ can be Local, Remote, or Unspecified (default)
 	typ Type
 
@@ -372,6 +378,19 @@ func (p *peer) Update(other Peer) error {
 	return nil
 }
 
+func (p *peer) GetVersions() (agent, protocol string) {
+	p.RLock()
+	defer p.RUnlock()
+	return p.agentVersion, p.protocolVersion
+}
+
+func (p *peer) SetVersions(agent, protocol string) {
+	p.Lock()
+	defer p.Unlock()
+	p.agentVersion = agent
+	p.protocolVersion = protocol
+}
+
 // WithKeyPair returns a Peer object with given keys.
 func WithKeyPair(sk ic.PrivKey, pk ic.PubKey) (Peer, error) {
 	if sk == nil && pk == nil {