diff --git a/src/App.vue b/src/App.vue
index 25c9074e7f3ccc933f663ec50db4158d82a0559d..da537dc8d7bbc6dea124eccb09244d81e09fe07f 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -7,7 +7,6 @@ import { RouterLink } from "vue-router";
     <nav>
       <RouterLink to="/">Home</RouterLink>
       <RouterLink to="/kubo">Kubo</RouterLink>
-      <RouterLink to="/ipns">IPNS</RouterLink>
       <RouterLink to="/index">Index</RouterLink>
       <RouterLink to="/diff">Diff</RouterLink>
       <RouterLink to="/io">IO</RouterLink>
diff --git a/src/assets/base.css b/src/assets/base.css
index 8816868a41b651f318dee87c6784ebcd6e29eca1..7c27c2e10c1ba1dc4c6f33b1b1ad80c9edcc6ab9 100644
--- a/src/assets/base.css
+++ b/src/assets/base.css
@@ -55,7 +55,6 @@
 *::after {
   box-sizing: border-box;
   margin: 0;
-  font-weight: normal;
 }
 
 body {
diff --git a/src/components/IpnsLink.vue b/src/components/IpnsLink.vue
index 5a5644a0196cf82ed3e88a1a93aead04fea4b312..d9b7777bc36cdd6b6b4f98d18a25f0fa4d88396e 100644
--- a/src/components/IpnsLink.vue
+++ b/src/components/IpnsLink.vue
@@ -10,5 +10,5 @@ const short = computed(() => props.ipns.slice(0, 5) + '...' + props.ipns.slice(-
 </script>
 
 <template>
-  <a target="_blank" :href="gatewayUrlIPNS(ipns)" class="mono">{{ short }}</a>
+  <a target="_blank" :href="gatewayUrlIPNS(ipns)" class="mono"><slot>{{ short }}</slot></a>
 </template>
diff --git a/src/indexer/ipns.ts b/src/indexer/ipns.ts
index d07d485102cdcd225e9fe2c3aef66b4470216a08..d09d749232348e90cbc291c5bb9ff7725a593143 100644
--- a/src/indexer/ipns.ts
+++ b/src/indexer/ipns.ts
@@ -11,9 +11,6 @@ export async function getSelfDdKeys(): Promise<DdKeys> {
     tamt: ks.get('dd_tamt')!,
     tamt_hist: ks.get('dd_tamt_hist')!,
     profiles: ks.get('dd_profiles')!,
-    ui_client_demo: ks.get('dd_ui_client_demo') || null,
-    ui_client_demo_hist: ks.get('dd_ui_client_demo_hist') || null,
-    ui_admin: ks.get('dd_ui_admin') || null
   }
   return keys
 }
diff --git a/src/indexer/types.ts b/src/indexer/types.ts
index f87867eed587fc1db38f433ffe84a76276e18eb6..b37cd4f75ca5d1946d365f1b5f93021a226feb0d 100644
--- a/src/indexer/types.ts
+++ b/src/indexer/types.ts
@@ -8,11 +8,8 @@ export interface DiffData {
   newItems: Array<[CID, IndexRequest]>
 }
 
-
 // this object allows to share a single ipns key with other datapods
 // so that they use components as bootstrap
-// each key can be replaced by their own version if they publish something in their name
-// or keep pointing to a name maintained by someone else
 export interface DdKeys {
   // root entry mapping to all the other ones below
   root: string
@@ -22,10 +19,6 @@ export interface DdKeys {
   tamt_hist: string
   // C+ profiles kinds grouped in a single tree for efficient indexing
   profiles: string
-  // demo client UI
-  ui_client_demo: string | null
-  // history of demo client UI
-  ui_client_demo_hist: string | null
-  // node admin UI
-  ui_admin: string | null
-}
\ No newline at end of file
+}
+// names of keys for iter since we can not easily get them programatically
+export const ddKeysNames = ['root', 'tamt', 'tamt_hist', 'profiles']
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 6e1d218263e4c864abcb984b19ae14c33403f782..3137835ce2167683840d1437b8ad6b56cb37d07d 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -10,9 +10,8 @@
     </p>
     <h2>Main menu</h2>
     <ul>
-      <li><RouterLink to="/">Home</RouterLink> -- here</li>
+      <li><RouterLink to="/">Home</RouterLink> – here</li>
       <li><RouterLink to="/kubo">Kubo</RouterLink></li>
-      <li><RouterLink to="/ipns">IPNS</RouterLink></li>
       <li><RouterLink to="/index">Index</RouterLink></li>
       <li><RouterLink to="/diff">Diff</RouterLink></li>
       <li><RouterLink to="/io">IO</RouterLink></li>
@@ -21,6 +20,7 @@
     <h2>Not in main menu</h2>
     <ul>
       <li><RouterLink to="/feed">Feed</RouterLink></li>
+      <li><RouterLink to="/ipns">IPNS</RouterLink></li>
     </ul>
   </main>
 </template>
diff --git a/src/views/IpnsView.vue b/src/views/IpnsView.vue
index f1ff2dab71d7b85eb0e0a06ffea8d274589ec5cc..dcc9e35e8be4cca9602f13c72a4acf88290f618e 100644
--- a/src/views/IpnsView.vue
+++ b/src/views/IpnsView.vue
@@ -1,56 +1,86 @@
 <script setup lang="ts">
+import { ref, type Ref, computed, onMounted, reactive, type ShallowReactive } from 'vue'
 import { kubo } from '@/kubo'
 import { emptyInode, type IndexHist } from '../types'
 import { EMPTY_NODE_CID } from '../consts'
 import { CID } from 'multiformats'
-import { ref, type Ref, computed, onMounted } from 'vue'
-import { ddKeys } from '../indexer/ipns'
+import { ddKeys as _ddKeys } from '../indexer/ipns'
+import { ddKeysNames, type DdKeys } from '../indexer/types'
+import IpnsLink from '@/components/IpnsLink.vue'
+import CidLink from '@/components/CidLink.vue'
 
-const targetMsg = ref('')
-const targetCID: Ref<CID | null> = ref(null)
-const histCID: Ref<CID | null> = ref(null)
+const ddKeys = _ddKeys as any // for easy manipulation
 
-const isValid = computed(() => {
+const targetCids: ShallowReactive<any> = reactive({})
+const targetCidsMsg: ShallowReactive<any> = reactive({})
+
+function set(k: string) {
   try {
-    CID.parse(targetMsg.value)
-    return true
-  } catch {
-    return false
+    const cid = CID.parse(targetCidsMsg[k])
+    targetCidsMsg[k] = ''
+    kubo.name
+      .publish(cid, { key: 'dd_' + k, ttl: '1s' })
+      .then(() => {
+        targetCids[k] = cid.toString()
+        if (k == 'tamt') {
+          // track it on the history
+          updateHist(cid)
+        }
+      })
+      .catch((e) => {
+        console.log(e)
+        targetCidsMsg[k] = 'error publishing'
+      })
+  } catch (e) {
+    console.log(e)
+    targetCidsMsg[k] = 'can not parse CID'
   }
-})
+}
 
-// inits indexing and publishes ipns entry for it
-async function initIndex() {
-  targetCID.value = EMPTY_NODE_CID
-  // publish result to ipns
-  kubo.name.publish(EMPTY_NODE_CID, { ttl: '1s', key: 'self' }).then(console.log)
-  // track it on the history
-  updateHist(EMPTY_NODE_CID)
+function reinitialize(k: string) {
+  switch (k) {
+    case 'tamt': {
+      console.log('reinitialize tamt')
+      targetCidsMsg.tamt = EMPTY_NODE_CID.toString()
+      set(k)
+      break
+    }
+    case 'tamt_hist': {
+      console.log('reinitialize tamt history')
+      initTamtHistOn(ddKeys.tamt)
+      break
+    }
+    case 'profiles': {
+      console.log('reinitialize profiles')
+      break
+    }
+    default:
+      console.log('unimplemented')
+  }
 }
 
 // inits indexing and publishes ipns entry for it
-async function initIndexHist() {
+async function initTamtHistOn(cid: CID) {
   const firstHist: IndexHist = {
     last_history: null,
-    current_index: targetCID.value!,
+    current_index: cid,
     number: 0,
     timestamp: Date.now()
   }
   const firstHistCID = await kubo.dag.put(firstHist)
-  kubo.name.publish(firstHistCID, { ttl: '1s', key: 'index_history' }).then(console.log)
+  kubo.name.publish(firstHistCID, { key: 'dd_tamt_hist', ttl: '1s' }).then(console.log)
 }
 
 // resolve given ipns
 async function resolveIPNS(ipns: string): Promise<CID> {
-  let cid = null
-  for await (const name of kubo.name.resolve(ipns, { nocache: true })) {
-    cid = CID.parse(name.slice(6))
+  for await (const name of kubo.name.resolve(ipns, { nocache: true, timeout: 100 })) {
+    return CID.parse(name.slice(6))
   }
-  return cid!
+  throw Error('could not resolve')
 }
 
 // update history chain with new cid
-async function updateHist(cid: CID) {
+async function updateHist(cid: CID): Promise<CID> {
   const lastHistCID = await resolveIPNS(ddKeys.tamt_hist)
   const lastHist = (await kubo.dag.get(lastHistCID)).value
   const newHist: IndexHist = {
@@ -61,48 +91,75 @@ async function updateHist(cid: CID) {
   }
   const newHistCID = await kubo.dag.put(newHist)
   kubo.name.publish(newHistCID, { ttl: '1s', key: 'index_history' })
-}
-
-// publish cid to IPNS
-function setTargetCid() {
-  if (isValid.value) {
-    const cid = CID.parse(targetMsg.value)
-    targetCID.value = cid
-    kubo.name.publish(cid, { ttl: '1s' })
-  } else {
-    targetCID.value = null
-  }
+  return newHistCID
 }
 
 onMounted(() => {
-  resolveIPNS(ddKeys.tamt).then((c) => (targetCID.value = c))
-  resolveIPNS(ddKeys.tamt_hist).then((c) => (histCID.value = c))
+  for (let k of ddKeysNames) {
+    resolveIPNS(ddKeys[k])
+      .then((c) => (targetCids[k] = c?.toString()))
+      .catch(console.log)
+  }
 })
 </script>
 
 <template>
   <div>
     <h1>IPNS</h1>
-    <p>Info about IPNS entries</p>
-    <h2>Index root</h2>
-    <p>Root node IPNS</p>
-    <p class="mono">{{ ddKeys.tamt }}</p>
-    <p>is pointing to</p>
-    <p class="mono">{{ targetCID }}</p>
-    <p>initialize empty index: <button @click="initIndex">reinitialize ⚠️</button></p>
+    <p>Info about Datapod IPNS entries. These keys are named with a "dd_" prefix.</p>
     <p>
-      or set to custom CID <br />
-      <input v-model="targetMsg" @keyup.enter="setTargetCid" size="50" />
-      <button v-on:click="setTargetCid">Set ⚠️</button>
+      To see all keys available in the node, not restricted to these ones, go to
+      <RouterLink to="/kubo">Kubo view</RouterLink>.
     </p>
-    <h2>Index history</h2>
-    <p>History IPNS</p>
-    <p class="mono">{{ ddKeys.tamt_hist }}</p>
-    <p>is pointing to</p>
-    <p class="mono">{{ histCID }}</p>
-    <p>reinitialize history to current target cid <button @click="initIndexHist">reinitialize ⚠️</button></p>
-    <p>and got to <RouterLink to="/index">index</RouterLink> to see more about index history</p>
+    <ul>
+      <li><b>dd_root</b> points to the object listing all the keys</li>
+      <li>
+        <b>dd_tamt</b> points to the root node of the TAMT, see more on <RouterLink to="/index">index view</RouterLink>.
+      </li>
+      <li>
+        <b>dd_tamt_hist</b> points to the head of the history of TAMT root, see more on
+        <RouterLink to="/index">index view</RouterLink>.
+      </li>
+      <li><b>dd_profiles</b> points to the root node of profiles index</li>
+    </ul>
+    <p>
+      In the table below you can edit your IPNS entires. Think of it as DNS and keep in mind that the datapod is using
+      it.
+    </p>
+    <br />
+    <table>
+      <thead>
+        <tr>
+          <th>name</th>
+          <th>target</th>
+          <th>set target</th>
+          <th>⚠️ reset</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr v-for="k in ddKeysNames">
+          <td>
+            <IpnsLink :ipns="ddKeys[k]">dd_{{ k }}</IpnsLink>
+          </td>
+          <td><CidLink v-if="targetCids[k]" :cid="targetCids[k]" /><template v-else>undefined</template></td>
+          <template v-if="k == 'root'">
+            <td class="center">-</td>
+            <td class="center">-</td>
+          </template>
+          <template v-else>
+            <td>
+              <input size="40" @keyup.enter="set(k)" v-model="targetCidsMsg[k]" /><button @click="set(k)">set</button>
+            </td>
+            <td class="center"><button @click="reinitialize(k)">reset</button></td>
+          </template>
+        </tr>
+      </tbody>
+    </table>
   </div>
 </template>
 
-<style scoped></style>
+<style scoped>
+.center {
+  text-align: center;
+}
+</style>
diff --git a/src/views/KuboView.vue b/src/views/KuboView.vue
index f8026e3449bd4194f613cd1297a0cfe3a789ec93..dfcd98acec94e8a436ce702a5ff75d314d0542a2 100644
--- a/src/views/KuboView.vue
+++ b/src/views/KuboView.vue
@@ -49,6 +49,7 @@ refresh()
     <p v-else>loading stats...<br /><br /><br /><br /><br /></p>
     <h2>Keys</h2>
     <p>Key prefixed by "dd" are used by the datapod. They should be listed in object published on dd_root.</p>
+    <p>To inspect and edit IPNS entries, go to <RouterLink to="/ipns">IPNS view</RouterLink>.</p>
     <table>
       <thead>
         <tr>