diff --git a/src/xen_unified.c b/src/xen_unified.c
index 1ab204d..9314725 100644
--- a/src/xen_unified.c
+++ b/src/xen_unified.c
@@ -222,6 +222,7 @@ xenUnifiedOpen (virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth, int f
 {
     int i, ret = VIR_DRV_OPEN_DECLINED;
     xenUnifiedPrivatePtr priv;
+    virDomainEventCallbackListPtr cbList;
 
     /* Refuse any scheme which isn't "xen://" or "http://". */
     if (uri->scheme &&
@@ -248,6 +249,13 @@ xenUnifiedOpen (virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth, int f
     }
     conn->privateData = priv;
 
+    /* Allocate callback list */
+    if (VIR_ALLOC(cbList) < 0) {
+        xenUnifiedError (NULL, VIR_ERR_NO_MEMORY, "allocating callback list");
+        return VIR_DRV_OPEN_ERROR;
+    }
+    priv->domainEventCallbacks = cbList;
+
     priv->handle = -1;
     priv->xendConfigVersion = -1;
     priv->type = -1;
@@ -345,6 +353,8 @@ xenUnifiedClose (virConnectPtr conn)
     int i;
 
     virCapabilitiesFree(priv->caps);
+    virDomainEventCallbackListFree(priv->domainEventCallbacks);
+
     for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
         if (priv->opened[i] && drivers[i]->close)
             (void) drivers[i]->close (conn);
@@ -1280,6 +1290,29 @@ xenUnifiedNodeGetFreeMemory (virConnectPtr conn)
     return(0);
 }
 
+static int
+xenUnifiedDomainEventRegister (virConnectPtr conn,
+                               void *callback,
+                               void *opaque)
+{
+    GET_PRIVATE (conn);
+    conn->refs++;
+    return virDomainEventCallbackListAdd(conn, priv->domainEventCallbacks,
+                                         callback, opaque);
+}
+
+static int
+xenUnifiedDomainEventDeregister (virConnectPtr conn,
+                                 void *callback)
+{
+    int ret;
+    GET_PRIVATE (conn);
+    ret = virDomainEventCallbackListRemove(conn, priv->domainEventCallbacks,
+                                            callback);
+    virUnrefConnect(conn);
+    return ret;
+}
+
 /*----- Register with libvirt.c, and initialise Xen drivers. -----*/
 
 #define HV_VERSION ((DOM0_INTERFACE_VERSION >> 24) * 1000000 +         \
@@ -1345,6 +1378,8 @@ static virDriver xenUnifiedDriver = {
     .domainBlockPeek	= xenUnifiedDomainBlockPeek,
     .nodeGetCellsFreeMemory = xenUnifiedNodeGetCellsFreeMemory,
     .getFreeMemory = xenUnifiedNodeGetFreeMemory,
+    .domainEventRegister = xenUnifiedDomainEventRegister,
+    .domainEventDeregister = xenUnifiedDomainEventDeregister,
 };
 
 /**
@@ -1364,3 +1399,130 @@ xenUnifiedRegister (void)
     return virRegisterDriver (&xenUnifiedDriver);
 }
 
+/**
+ * xenUnifiedDomainInfoListFree:
+ *
+ * Free the Domain Info List
+ */
+void
+xenUnifiedDomainInfoListFree(xenUnifiedDomainInfoListPtr list)
+{
+    int i;
+    for (i=0; i<list->count; i++) {
+        VIR_FREE(list->doms[i]->name);
+        VIR_FREE(list->doms[i]->uuid);
+    }
+    VIR_FREE(list);
+}
+
+/**
+ * xenUnifiedAddDomainInfo:
+ *
+ * Add name and uuid to the domain info list
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int
+xenUnifiedAddDomainInfo(xenUnifiedDomainInfoListPtr list,
+                             char *name, char *uuid)
+{
+    xenUnifiedDomainInfoPtr info;
+    int n;
+
+    /* check if we already have this callback on our list */
+    for (n=0; n < list->count; n++) {
+        if( STREQ(list->doms[n]->name, name) &&
+            STREQ(list->doms[n]->uuid, uuid)) {
+            DEBUG0("WARNING: dom already tracked");
+            return -1;
+        }
+    }
+
+    if (VIR_ALLOC(info) < 0) {
+        xenUnifiedError (NULL, VIR_ERR_NO_MEMORY, "allocating info");
+        return -1;
+    }
+    info->name   = strdup(name);
+    info->uuid  = strdup(uuid);
+
+    /* Make space on list */
+    n = list->count;
+    if (VIR_REALLOC_N(list->doms, n + 1) < 0) {
+        xenUnifiedError (NULL, VIR_ERR_NO_MEMORY, "reallocating list");
+        VIR_FREE(info);
+        return -1;
+    }
+
+    list->doms[n] = info;
+    list->count++;
+    return 0;
+}
+
+/**
+ * xenUnifiedRemoveDomainInfo:
+ *
+ * Removes name and uuid to the domain info list
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int
+xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr list,
+                             char *name, char *uuid)
+{
+    int i;
+    for (i = 0 ; i < list->count ; i++) {
+        if( STREQ(list->doms[i]->name, name) &&
+            STREQ(list->doms[i]->uuid, uuid)) {
+            VIR_FREE(list->doms[i]->name);
+            VIR_FREE(list->doms[i]->uuid);
+            VIR_FREE(list->doms[i]);
+
+            if (i < (list->count - 1))
+                memmove(list->doms + i,
+                        list->doms + i + 1,
+                        sizeof(*(list->doms)) *
+                                (list->count - (i + 1)));
+
+            if (VIR_REALLOC_N(list->doms,
+                              list->count - 1) < 0) {
+                ; /* Failure to reduce memory allocation isn't fatal */
+            }
+            list->count--;
+
+            return 0;
+        }
+    }
+    return -1;
+}
+
+/**
+ * xenUnifiedDomainEventDispatch:
+ *
+ * Dispatch domain events to registered callbacks
+ *
+ */
+ void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
+                                    virDomainPtr dom,
+                                    virDomainEventType evt)
+{
+    int i;
+    virDomainEventCallbackListPtr cbList;
+
+    if(!priv) return;
+
+    cbList = priv->domainEventCallbacks;
+    if(!cbList) return;
+
+    for(i=0 ; i < cbList->count ; i++) {
+        if(cbList->callbacks[i] && cbList->callbacks[i]->cb) {
+            if (dom) {
+                DEBUG("Dispatching callback %p %p event %d",
+                        cbList->callbacks[i],
+                        cbList->callbacks[i]->cb, evt);
+                cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
+                                         dom, evt,
+                                         cbList->callbacks[i]->opaque);
+            }
+        }
+    }
+}
diff --git a/src/xen_unified.h b/src/xen_unified.h
index 48415a8..2936a86 100644
--- a/src/xen_unified.h
+++ b/src/xen_unified.h
@@ -14,6 +14,8 @@
 #include "internal.h"
 #include "capabilities.h"
 #include "driver.h"
+#include "xs_internal.h"
+#include "domain_event.h"
 
 #ifndef HAVE_WINSOCK2_H
 #include <sys/un.h>
@@ -85,6 +87,25 @@ struct xenUnifiedDriver {
         virDrvDomainSetSchedulerParameters domainSetSchedulerParameters;
 };
 
+/* xenUnifiedDomainInfoPtr:
+ * The minimal state we have about active domains
+ * This is the minmal info necessary to still get a
+ * virDomainPtr when the domain goes away
+ */
+struct _xenUnifiedDomainInfo {
+    char *name;
+    char *uuid;
+};
+typedef struct _xenUnifiedDomainInfo xenUnifiedDomainInfo;
+typedef xenUnifiedDomainInfo *xenUnifiedDomainInfoPtr;
+
+struct _xenUnifiedDomainInfoList {
+    unsigned int count;
+    xenUnifiedDomainInfoPtr *doms;
+};
+typedef struct _xenUnifiedDomainInfoList xenUnifiedDomainInfoList;
+typedef xenUnifiedDomainInfoList *xenUnifiedDomainInfoListPtr;
+
 /* xenUnifiedPrivatePtr:
  *
  * Per-connection private data, stored in conn->privateData.  All Xen
@@ -113,6 +134,15 @@ struct _xenUnifiedPrivate {
      * xen_unified.c.
      */
     int opened[XEN_UNIFIED_NR_DRIVERS];
+
+    /* A list of xenstore watches */
+    xenStoreWatchListPtr xsWatchList;
+
+    /* An list of active domain name/uuids */
+    xenUnifiedDomainInfoListPtr domInfoList;
+
+    /* An list of callbacks */
+    virDomainEventCallbackListPtr domainEventCallbacks;
 };
 
 typedef struct _xenUnifiedPrivate *xenUnifiedPrivatePtr;
@@ -122,4 +152,12 @@ int xenNbCells(virConnectPtr conn);
 int xenNbCpus(virConnectPtr conn);
 char *xenDomainUsedCpus(virDomainPtr dom);
 
+void xenUnifiedDomainInfoListFree(xenUnifiedDomainInfoListPtr info);
+int  xenUnifiedAddDomainInfo(xenUnifiedDomainInfoListPtr info,
+                             char *name, char *uuid);
+int  xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr info,
+                             char *name, char *uuid);
+void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
+                                    virDomainPtr dom,
+                                    virDomainEventType evt);
 #endif /* __VIR_XEN_UNIFIED_H__ */
diff --git a/src/xs_internal.c b/src/xs_internal.c
index b096acd..642f9ab 100644
--- a/src/xs_internal.c
+++ b/src/xs_internal.c
@@ -29,6 +29,8 @@
 #include "virterror_internal.h"
 #include "datatypes.h"
 #include "driver.h"
+#include "memory.h"
+#include "event.h"
 #include "xen_unified.h"
 #include "xs_internal.h"
 #include "xen_internal.h" /* for xenHypervisorCheckID */
@@ -301,9 +303,55 @@ xenStoreOpen(virConnectPtr conn,
             virXenStoreError(NULL, VIR_ERR_NO_XEN,
                                  "%s", _("failed to connect to Xen Store"));
         }
-        return (-1);
+        return -1;
     }
-    return (0);
+
+#ifndef PROXY
+    /* Init domInfoList */
+    if ( VIR_ALLOC(priv->domInfoList ) < 0) {
+        virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
+                                 "%s", _("failed to allocate domInfoList"));
+        return -1;
+    }
+
+    /* Init watch list before filling in domInfoList,
+       so we can know if it is the first time through
+       when the callback fires */
+    if ( VIR_ALLOC(priv->xsWatchList) < 0 ) {
+        virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
+                                 "%s", _("failed to allocate xsWatchList"));
+        return -1;
+    }
+
+    /* This will get called once at start */
+    if ( xenStoreAddWatch(conn, "@releaseDomain",
+                     "releaseDomain", xenStoreDomainReleased, priv) < 0 )
+    {
+        DEBUG0("Error Adding Watch @releaseDomain\n");
+        return -1;
+    }
+
+    /* The initial call of this will fill domInfoList */
+    if( xenStoreAddWatch(conn, "@introduceDomain",
+                     "introduceDomain", xenStoreDomainIntroduced, priv) < 0 )
+    {
+        DEBUG0("Error Adding Watch @introduceDomain\n");
+        return -1;
+    }
+
+    /* Add an event handle */
+    if (virEventAddHandle(xs_fileno(priv->xshandle),
+                          VIR_EVENT_HANDLE_READABLE,
+                          xenStoreWatchEvent,
+                          conn) < 0) {
+        virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
+                                 "%s", _("failed to handle"));
+
+        return -1;
+    }
+
+#endif //PROXY
+    return 0;
 }
 
 /**
@@ -317,6 +365,7 @@ xenStoreOpen(virConnectPtr conn,
 int
 xenStoreClose(virConnectPtr conn)
 {
+    int fd;
     xenUnifiedPrivatePtr priv;
 
     if (conn == NULL) {
@@ -325,10 +374,23 @@ xenStoreClose(virConnectPtr conn)
     }
 
     priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+    xenStoreRemoveWatch(conn, "@introduceDomain", "introduceDomain");
+    xenStoreRemoveWatch(conn, "@releaseDomain", "releaseDomain");
+
+    xenStoreWatchListFree(priv->xsWatchList);
+#ifndef PROXY
+    xenUnifiedDomainInfoListFree(priv->domInfoList);
+#endif
     if (priv->xshandle == NULL)
         return(-1);
 
+    fd = xs_fileno(priv->xshandle);
+    virEventRemoveHandle(fd);
+    close(fd);
     xs_daemon_close(priv->xshandle);
+    priv->xshandle = NULL;
+
     return (0);
 }
 
@@ -921,3 +983,345 @@ char *xenStoreDomainGetName(virConnectPtr conn,
     return xs_read(priv->xshandle, 0, prop, &len);
 }
 
+#ifndef PROXY
+char *xenStoreDomainGetUUID(virConnectPtr conn,
+                            int id) {
+    char prop[200];
+    xenUnifiedPrivatePtr priv;
+    unsigned int len;
+    char *vm_string;
+    char *ret;
+
+    priv = (xenUnifiedPrivatePtr) conn->privateData;
+    if (priv->xshandle == NULL)
+        return(NULL);
+
+    snprintf(prop, 199, "/local/domain/%d/vm", id);
+    prop[199] = 0;
+    // This will return something like
+    // /vm/00000000-0000-0000-0000-000000000000
+    vm_string = xs_read(priv->xshandle, 0, prop, &len);
+
+    // remove "/vm/"
+    ret = strdup(vm_string + 4);
+
+    VIR_FREE(vm_string);
+
+    return ret;
+}
+#endif //PROXY
+
+void xenStoreWatchListFree(xenStoreWatchListPtr list)
+{
+    int i;
+    for (i=0; i<list->count; i++) {
+        VIR_FREE(list->watches[i]->path);
+        VIR_FREE(list->watches[i]->token);
+        VIR_FREE(list->watches[i]);
+    }
+    VIR_FREE(list);
+}
+
+int xenStoreAddWatch(virConnectPtr conn,
+                     const char *path,
+                     const char *token,
+                     xenStoreWatchCallback cb,
+                     void *opaque)
+{
+    xenStoreWatchPtr watch;
+    int n;
+    xenStoreWatchListPtr list;
+    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+    if (priv->xshandle == NULL)
+        return -1;
+
+    list = priv->xsWatchList;
+    if(!list)
+        return -1;
+
+    /* check if we already have this callback on our list */
+    for (n=0; n < list->count; n++) {
+        if( STREQ(list->watches[n]->path, path) &&
+            STREQ(list->watches[n]->token, token)) {
+            DEBUG0("WARNING: Watch already tracked");
+            return -1;
+        }
+    }
+
+    if (VIR_ALLOC(watch) < 0)
+        return -1;
+    watch->path   = strdup(path);
+    watch->token  = strdup(token);
+    watch->cb     = cb;
+    watch->opaque = opaque;
+
+    /* Make space on list */
+    n = list->count;
+    if (VIR_REALLOC_N(list->watches, n + 1) < 0) {
+        DEBUG0("Error reallocating list");
+        VIR_FREE(watch);
+        return -1;
+    }
+
+    list->watches[n] = watch;
+    list->count++;
+
+    conn->refs++;
+
+    return xs_watch(priv->xshandle, watch->path, watch->token);
+}
+
+int xenStoreRemoveWatch(virConnectPtr conn,
+                        const char *path,
+                        const char *token)
+{
+    int i;
+    xenStoreWatchListPtr list;
+    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+    if (priv->xshandle == NULL)
+        return -1;
+
+    list = priv->xsWatchList;
+    if(!list)
+        return -1;
+
+    for (i = 0 ; i < list->count ; i++) {
+        if( STREQ(list->watches[i]->path, path) &&
+            STREQ(list->watches[i]->token, token)) {
+
+            xs_unwatch(priv->xshandle,
+                       list->watches[i]->path,
+                       list->watches[i]->path);
+
+            VIR_FREE(list->watches[i]->path);
+            VIR_FREE(list->watches[i]->token);
+            VIR_FREE(list->watches[i]);
+
+            if (i < (list->count - 1))
+                memmove(list->watches + i,
+                        list->watches + i + 1,
+                        sizeof(*(list->watches)) *
+                                (list->count - (i + 1)));
+
+            if (VIR_REALLOC_N(list->watches,
+                              list->count - 1) < 0) {
+                ; /* Failure to reduce memory allocation isn't fatal */
+            }
+            list->count--;
+#ifndef PROXY
+            virUnrefConnect(conn);
+#endif
+            return 0;
+        }
+    }
+    return -1;
+}
+
+xenStoreWatchPtr xenStoreFindWatch(xenStoreWatchListPtr list,
+                                   const char *path,
+                                   const char *token)
+{
+    int i;
+    for (i = 0 ; i < list->count ; i++)
+        if( STREQ(path, list->watches[i]->path) &&
+            STREQ(token, list->watches[i]->token) )
+            return list->watches[i];
+
+    return NULL;
+}
+
+void xenStoreWatchEvent(int fd ATTRIBUTE_UNUSED,
+                        int events ATTRIBUTE_UNUSED,
+                        void *data)
+{
+    char		 **event;
+    char		 *path;
+    char		 *token;
+    unsigned int	 stringCount;
+    xenStoreWatchPtr     sw;
+
+    virConnectPtr        conn = data;
+    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+    if(!priv) return;
+    if(!priv->xshandle) return;
+
+    event = xs_read_watch(priv->xshandle, &stringCount);
+    if (!event)
+        return;
+
+    path  = event[XS_WATCH_PATH];
+    token = event[XS_WATCH_TOKEN];
+
+    sw = xenStoreFindWatch(priv->xsWatchList, path, token);
+    if( sw )
+        sw->cb(conn, path, token, sw->opaque);
+    VIR_FREE(event);
+}
+
+#ifndef PROXY
+/* The domain callback for the @introduceDomain watch */
+int xenStoreDomainIntroduced(virConnectPtr conn,
+                             const char *path ATTRIBUTE_UNUSED,
+                             const char *token ATTRIBUTE_UNUSED,
+                             void *opaque)
+{
+    int i, j;
+    int new_domain_cnt;
+    int *new_domids;
+    char *name;
+    char *uuid;
+    int nread;
+
+    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) opaque;
+
+retry:
+    new_domain_cnt = xenStoreNumOfDomains(conn);
+    if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
+        virXenStoreError(NULL, VIR_ERR_NO_MEMORY,
+                                 "%s", _("failed to allocate domids"));
+        return -1;
+    }
+    nread = xenStoreListDomains(conn, new_domids, new_domain_cnt);
+    if (nread != new_domain_cnt) {
+        // mismatch. retry this read
+        VIR_FREE(new_domids);
+        goto retry;
+    }
+
+    // Initial callback, fill list (This should at least contain dom0)
+    if(!priv->domInfoList->count) {
+        for (i=0 ; i < new_domain_cnt ; i++) {
+            name = xenStoreDomainGetName(conn, new_domids[i]);
+            uuid = xenStoreDomainGetUUID(conn, new_domids[i]);
+            xenUnifiedAddDomainInfo(priv->domInfoList,name,uuid);
+            VIR_FREE(name);
+            VIR_FREE(uuid);
+        }
+        VIR_FREE(new_domids);
+        return 0;
+    }
+
+    for (i=0 ; i < new_domain_cnt ; i++) {
+        if (!(name = xenStoreDomainGetName(conn, new_domids[i]))) {
+            continue;
+        }
+        if (!(uuid = xenStoreDomainGetUUID(conn, new_domids[i]))) {
+            VIR_FREE(name);
+            continue;
+        }
+        /* We must iterate over both lists to avoid a race where
+           2 domains were created by the time we get here */
+        for (j=0 ; j < priv->domInfoList->count ; j++) {
+            if( !STREQ(name, priv->domInfoList->doms[j]->name) ||
+                !STREQ(uuid, priv->domInfoList->doms[j]->uuid) ) {
+                virDomainPtr dom = virGetDomain(conn, name, (unsigned char*)uuid);
+                if(dom) {
+                    dom->id = new_domids[i];
+
+                    /* This domain was not in the old list. Emit an event */
+                    xenUnifiedDomainEventDispatch(priv, dom,
+                                                  VIR_DOMAIN_EVENT_STARTED);
+
+                    /* Add to the list */
+                    xenUnifiedAddDomainInfo(priv->domInfoList,name,uuid);
+                }
+                virUnrefDomain(dom);
+            }
+        }
+
+        VIR_FREE(name);
+        VIR_FREE(uuid);
+    }
+    VIR_FREE(new_domids);
+    return 0;
+}
+
+/* The domain callback for the @destroyDomain watch */
+int xenStoreDomainReleased(virConnectPtr conn,
+                            const char *path  ATTRIBUTE_UNUSED,
+                            const char *token ATTRIBUTE_UNUSED,
+                            void *opaque)
+{
+    int i, j, found, removed;
+    int new_domain_cnt;
+    int *new_domids;
+    char *name;
+    char *uuid;
+    int nread;
+
+    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) opaque;
+
+    if(!priv->domInfoList->count) return 0;
+
+retry:
+    new_domain_cnt = xenStoreNumOfDomains(conn);
+
+    if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
+        virXenStoreError(NULL, VIR_ERR_NO_MEMORY,
+                                 "%s", _("failed to allocate domids"));
+        return -1;
+    }
+    nread = xenStoreListDomains(conn, new_domids, new_domain_cnt);
+    if (nread != new_domain_cnt) {
+        // mismatch. retry this read
+        VIR_FREE(new_domids);
+        goto retry;
+    }
+
+    removed = 0;
+    for (j=0 ; j < priv->domInfoList->count ; j++) {
+        found = 0;
+        for (i=0 ; i < new_domain_cnt ; i++) {
+            if (!(name = xenStoreDomainGetName(conn, new_domids[i]))) {
+                continue;
+            }
+
+            if (!(uuid = xenStoreDomainGetUUID(conn, new_domids[i]))) {
+                VIR_FREE(name);
+                continue;
+            }
+
+            if( STREQ(name, priv->domInfoList->doms[j]->name) ||
+                STREQ(uuid, priv->domInfoList->doms[j]->uuid) ) {
+                found = 1;
+                VIR_FREE(name);
+                VIR_FREE(uuid);
+                break;
+            }
+
+            VIR_FREE(name);
+            VIR_FREE(uuid);
+        }
+
+        if (!found) {
+              virDomainPtr dom = virGetDomain(conn,
+                                            priv->domInfoList->doms[j]->name,
+                            (unsigned char*)priv->domInfoList->doms[j]->uuid);
+            if(dom) {
+                dom->id = -1;
+                /* This domain was not in the new list. Emit an event */
+                xenUnifiedDomainEventDispatch(priv, dom,
+                                              VIR_DOMAIN_EVENT_STOPPED);
+                 /* Remove from the list */
+                xenUnifiedRemoveDomainInfo(priv->domInfoList,
+                                            priv->domInfoList->doms[j]->name,
+                                            priv->domInfoList->doms[j]->uuid);
+
+                virUnrefDomain(dom);
+                removed=1;
+            }
+        }
+    }
+
+    VIR_FREE(new_domids);
+    if(!removed) {
+        // xenstore sometimes calls us back before
+        // domids are fully torn down
+        usleep(1000);
+        goto retry;
+    }
+    return 0;
+}
+#endif //PROXY
diff --git a/src/xs_internal.h b/src/xs_internal.h
index 6163ebc..006e0e1 100644
--- a/src/xs_internal.h
+++ b/src/xs_internal.h
@@ -52,5 +52,56 @@ char *		xenStoreDomainGetDiskID(virConnectPtr conn,
                                          const char *dev);
 char *          xenStoreDomainGetName(virConnectPtr conn,
                                       int id);
+char *          xenStoreDomainGetUUID(virConnectPtr conn,
+                                      int id);
+
+typedef int (*xenStoreWatchCallback)(virConnectPtr conn,
+                                     const char *path,
+                                     const char *token,
+                                     void *opaque);
+
+struct _xenStoreWatch {
+    char *path;
+    char *token;
+    xenStoreWatchCallback cb;
+    void *opaque;
+};
+typedef struct _xenStoreWatch xenStoreWatch;
+typedef xenStoreWatch *xenStoreWatchPtr;
+
+struct _xenStoreWatchList {
+    unsigned int count;
+    xenStoreWatchPtr *watches;
+};
+typedef struct _xenStoreWatchList xenStoreWatchList;
+typedef xenStoreWatchList *xenStoreWatchListPtr;
+
+
+void            xenStoreWatchListFree(xenStoreWatchListPtr head);
+
+int             xenStoreAddWatch(virConnectPtr conn,
+                                 const char *path,
+                                 const char *token,
+                                 xenStoreWatchCallback cb,
+                                 void *opaque);
+int             xenStoreRemoveWatch(virConnectPtr conn,
+                                    const char *path,
+                                    const char *token);
+xenStoreWatchPtr xenStoreFindWatch(xenStoreWatchListPtr list,
+                                  const char *path,
+                                  const char *token);
+
+void xenStoreWatchEvent(int fd, int events, void *data);
+
+/* domain events */
+int xenStoreDomainIntroduced(virConnectPtr conn,
+                             const char *path,
+                             const char *token,
+                             void *opaque);
+int xenStoreDomainReleased(virConnectPtr conn,
+                            const char *path,
+                            const char *token,
+                            void *opaque);
 
+int xenStoreDomainEventEmitted(virDomainEventType evt);
 #endif /* __VIR_XS_INTERNAL_H__ */
