diff --git a/forum-network/notes/client-or-ui.md b/forum-network/notes/client-or-ui.md
deleted file mode 100644
index ad24afd..0000000
--- a/forum-network/notes/client-or-ui.md
+++ /dev/null
@@ -1,9 +0,0 @@
-## Client/UI
-
-Voting consists of staking operations performed by software operated by owners of EOA.
-
-This software may be referred to as "The UI". It may also be considered "a client".
-
-It will need to be a network-connected application. It will need a certain minimum of RAM,
-and for some features disk storage,
-and for some features uptime .
diff --git a/forum-network/notes/client.md b/forum-network/notes/client.md
index 55df288..ee6db86 100644
--- a/forum-network/notes/client.md
+++ b/forum-network/notes/client.md
@@ -1,5 +1,18 @@
-# Client Operations
+## Client
 
-Client must communicate with one or more servers.
+Clients play a key role in an MVPR DAO.
 
-Client must build a local view
+Clients must be operated by reputation holders.
+
+Clients are the agents that submit posts to the forum, initiate validation pools, and vote in validation pools.
+
+We sometimes refer to the client as "the UI".
+
+It will need to be a network-connected application. It will need a certain minimum of RAM,
+and for some features disk storage,
+and for some features uptime .
+
+The behavior of the client constitutes what we refer to as the DAO's "soft protocols".
+
+Malicious actors may freely modify their own client's behavior.
+Therefore honest clients must engage in policing to preserve the integrity of the network.
diff --git a/forum-network/src/classes/dao/client.js b/forum-network/src/classes/dao/client.js
new file mode 100644
index 0000000..366fa7f
--- /dev/null
+++ b/forum-network/src/classes/dao/client.js
@@ -0,0 +1,6 @@
+export class Client {
+  constructor(dao, expert) {
+    this.dao = dao;
+    this.expert = expert;
+  }
+}
diff --git a/forum-network/src/classes/display/box.js b/forum-network/src/classes/display/box.js
index bee1f88..1ed666a 100644
--- a/forum-network/src/classes/display/box.js
+++ b/forum-network/src/classes/display/box.js
@@ -5,7 +5,9 @@ export class Box {
   constructor(name, parentEl, options = {}) {
     this.name = name;
     this.el = document.createElement('div');
-    this.el.id = `box_${randomID()}`;
+    this.el.box = this;
+    const id = options.id ?? randomID();
+    this.el.id = `${parentEl.id}_box_${id}`;
     this.el.classList.add('box');
     if (name) {
       this.el.setAttribute('box-name', name);
diff --git a/forum-network/src/classes/display/document.js b/forum-network/src/classes/display/document.js
new file mode 100644
index 0000000..87c6bbf
--- /dev/null
+++ b/forum-network/src/classes/display/document.js
@@ -0,0 +1,30 @@
+import { Box } from './box.js';
+import { Form } from './form.js';
+
+/**
+ * @example
+ * ```typescript
+ * const doc = new Document();
+ * const form1 = doc.form();
+ * ```
+ */
+export class Document extends Box {
+  form() {
+    return this.addElement(new Form(this));
+  }
+
+  remarks(text, opts) {
+    return this.addElement(new Box('Remark', this.el, opts).setInnerHTML(text));
+  }
+
+  addElement(element) {
+    this.elements = this.elements ?? [];
+    this.elements.push(element);
+    return this;
+  }
+
+  get lastElement() {
+    if (!this.elements?.length) return null;
+    return this.elements[this.elements.length - 1];
+  }
+}
diff --git a/forum-network/src/classes/display/form.js b/forum-network/src/classes/display/form.js
new file mode 100644
index 0000000..80b6cb2
--- /dev/null
+++ b/forum-network/src/classes/display/form.js
@@ -0,0 +1,57 @@
+import { randomID } from '../../util/helpers.js';
+import { Box } from './box.js';
+
+const updateValuesOnEventTypes = ['keyup', 'mouseup'];
+
+export class FormElement extends Box {
+  constructor(name, parentEl, opts) {
+    super(name, parentEl, opts);
+    this.id = opts.id ?? name;
+    const { cb } = opts;
+    if (cb) {
+      updateValuesOnEventTypes.forEach((eventType) => this.el.addEventListener(eventType, () => {
+        cb(this);
+      }));
+      cb(this);
+    }
+  }
+}
+
+export class Button extends FormElement { }
+
+export class TextField extends FormElement {
+  constructor(name, parentEl, opts) {
+    super(name, parentEl, opts);
+    this.input = document.createElement('input');
+    this.el.appendChild(this.input);
+  }
+
+  get value() {
+    return this.input?.value;
+  }
+}
+
+export class TextArea extends FormElement { }
+
+export class Form {
+  constructor(document, opts = {}) {
+    this.document = document;
+    this.items = [];
+    this.id = opts.id ?? `form_${randomID()}`;
+  }
+
+  button(opts) {
+    this.items.push(new Button(opts.name, this.document.el, opts));
+    return this;
+  }
+
+  textField(opts) {
+    this.items.push(new TextField(opts.name, this.document.el, opts));
+    return this;
+  }
+
+  textArea(opts) {
+    this.items.push(new TextArea(opts.name, this.document.el, opts));
+    return this;
+  }
+}
diff --git a/forum-network/src/classes/display/scene.js b/forum-network/src/classes/display/scene.js
index 8f62ad1..3b14ec6 100644
--- a/forum-network/src/classes/display/scene.js
+++ b/forum-network/src/classes/display/scene.js
@@ -6,6 +6,7 @@ import { Table } from './table.js';
 import { Flowchart } from './flowchart.js';
 import { Controls } from './controls.js';
 import { Box } from './box.js';
+import { Document } from './document.js';
 
 export class Scene {
   constructor(name, rootBox) {
@@ -86,6 +87,24 @@ export class Scene {
     return this;
   }
 
+  /**
+   *
+   * @param {string} name
+   * @param {(Document): Document} cb
+   * @returns {Scene}
+   */
+  withDocument(name, cb) {
+    this.documents = this.documents ?? [];
+    const doc = new Document(name, this.middleSection.el);
+    this.documents.push(cb ? cb(doc) : doc);
+    return this;
+  }
+
+  get lastDocument() {
+    if (!this.documents?.length) return null;
+    return this.documents[this.documents.length - 1];
+  }
+
   registerActor(actor) {
     this.actors.add(actor);
     if (actor.options.announce) {
diff --git a/forum-network/src/index.html b/forum-network/src/index.html
index 86d1514..3c3e1fe 100644
--- a/forum-network/src/index.html
+++ b/forum-network/src/index.html
@@ -28,6 +28,12 @@
       
Multiple posts with overlapping authors
     
   
+  
   
@@ -38,6 +44,7 @@
     Debounce
     Flowchart
     Mocha
+    Input
   
   
     
diff --git a/forum-network/src/tests/all.test.html b/forum-network/src/tests/all.test.html
index 067797a..12ca110 100644
--- a/forum-network/src/tests/all.test.html
+++ b/forum-network/src/tests/all.test.html
@@ -37,6 +37,7 @@
 
 
 
+
 
+
+
+
+
diff --git a/forum-network/src/tests/input.test.html b/forum-network/src/tests/input.test.html
new file mode 100644
index 0000000..b2b35e1
--- /dev/null
+++ b/forum-network/src/tests/input.test.html
@@ -0,0 +1,26 @@
+
+
+
+  Input
+  
+  
+  
+
+
+
+  
+  
+  
+
+
+
+
+
+
diff --git a/forum-network/src/tests/scripts/client/client1.test.js b/forum-network/src/tests/scripts/client/client1.test.js
new file mode 100644
index 0000000..b5e7e9c
--- /dev/null
+++ b/forum-network/src/tests/scripts/client/client1.test.js
@@ -0,0 +1,26 @@
+import { mochaRun } from '../../../util/helpers.js';
+import { ForumTest } from '../forum.test-util.js';
+import { Client } from '../../../classes/dao/client.js';
+
+describe('Forum', function tests() {
+  this.timeout(0);
+
+  const forumTest = new ForumTest({ displayAuthors: false });
+  let client;
+
+  before(async () => {
+    await forumTest.setup();
+    await forumTest.newExpert();
+    await forumTest.newExpert();
+
+    client = new Client(forumTest.dao, forumTest.experts[0]);
+  });
+
+  it('Expert can run a client', async () => {
+    client.should.not.be.undefined;
+    client.dao.should.equal(forumTest.dao);
+    client.expert.should.equal(forumTest.experts[0]);
+  });
+});
+
+mochaRun();
diff --git a/forum-network/src/tests/scripts/forum/forum.test-util.js b/forum-network/src/tests/scripts/forum.test-util.js
similarity index 86%
rename from forum-network/src/tests/scripts/forum/forum.test-util.js
rename to forum-network/src/tests/scripts/forum.test-util.js
index 9aa34d5..02e85d5 100644
--- a/forum-network/src/tests/scripts/forum/forum.test-util.js
+++ b/forum-network/src/tests/scripts/forum.test-util.js
@@ -1,9 +1,9 @@
-import { Box } from '../../../classes/display/box.js';
-import { Scene } from '../../../classes/display/scene.js';
-import { Expert } from '../../../classes/actors/expert.js';
-import { PostContent } from '../../../classes/supporting/post-content.js';
-import { DAO } from '../../../classes/dao/dao.js';
-import { delayOrWait } from '../../../classes/display/controls.js';
+import { Box } from '../../classes/display/box.js';
+import { Scene } from '../../classes/display/scene.js';
+import { Expert } from '../../classes/actors/expert.js';
+import { PostContent } from '../../classes/supporting/post-content.js';
+import { DAO } from '../../classes/dao/dao.js';
+import { delayOrWait } from '../../classes/display/controls.js';
 
 export class ForumTest {
   constructor(options) {
diff --git a/forum-network/src/tests/scripts/forum/forum1.test.js b/forum-network/src/tests/scripts/forum/forum1.test.js
index b2e8895..38536e1 100644
--- a/forum-network/src/tests/scripts/forum/forum1.test.js
+++ b/forum-network/src/tests/scripts/forum/forum1.test.js
@@ -1,5 +1,5 @@
 import { mochaRun } from '../../../util/helpers.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum10.test.js b/forum-network/src/tests/scripts/forum/forum10.test.js
index 6327ae0..21430a3 100644
--- a/forum-network/src/tests/scripts/forum/forum10.test.js
+++ b/forum-network/src/tests/scripts/forum/forum10.test.js
@@ -1,5 +1,5 @@
 import { mochaRun } from '../../../util/helpers.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum11.test.js b/forum-network/src/tests/scripts/forum/forum11.test.js
index 0b144cc..04dcc92 100644
--- a/forum-network/src/tests/scripts/forum/forum11.test.js
+++ b/forum-network/src/tests/scripts/forum/forum11.test.js
@@ -1,5 +1,5 @@
 import { mochaRun } from '../../../util/helpers.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum2.test.js b/forum-network/src/tests/scripts/forum/forum2.test.js
index 71b1e76..fa98a90 100644
--- a/forum-network/src/tests/scripts/forum/forum2.test.js
+++ b/forum-network/src/tests/scripts/forum/forum2.test.js
@@ -1,5 +1,5 @@
 import { mochaRun } from '../../../util/helpers.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum3.test.js b/forum-network/src/tests/scripts/forum/forum3.test.js
index 1fd49e1..529298b 100644
--- a/forum-network/src/tests/scripts/forum/forum3.test.js
+++ b/forum-network/src/tests/scripts/forum/forum3.test.js
@@ -1,5 +1,5 @@
 import { mochaRun } from '../../../util/helpers.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum4.test.js b/forum-network/src/tests/scripts/forum/forum4.test.js
index 1a35b13..097d7e2 100644
--- a/forum-network/src/tests/scripts/forum/forum4.test.js
+++ b/forum-network/src/tests/scripts/forum/forum4.test.js
@@ -1,5 +1,5 @@
 import { mochaRun } from '../../../util/helpers.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum5.test.js b/forum-network/src/tests/scripts/forum/forum5.test.js
index b6c0a34..5988001 100644
--- a/forum-network/src/tests/scripts/forum/forum5.test.js
+++ b/forum-network/src/tests/scripts/forum/forum5.test.js
@@ -1,5 +1,5 @@
 import { mochaRun } from '../../../util/helpers.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum6.test.js b/forum-network/src/tests/scripts/forum/forum6.test.js
index 69ddd39..ab32aba 100644
--- a/forum-network/src/tests/scripts/forum/forum6.test.js
+++ b/forum-network/src/tests/scripts/forum/forum6.test.js
@@ -1,6 +1,6 @@
 import { mochaRun } from '../../../util/helpers.js';
 import { EPSILON } from '../../../util/constants.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum7.test.js b/forum-network/src/tests/scripts/forum/forum7.test.js
index 83cbf59..1a0d293 100644
--- a/forum-network/src/tests/scripts/forum/forum7.test.js
+++ b/forum-network/src/tests/scripts/forum/forum7.test.js
@@ -1,5 +1,5 @@
 import { mochaRun } from '../../../util/helpers.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum8.test.js b/forum-network/src/tests/scripts/forum/forum8.test.js
index d695782..63da1ed 100644
--- a/forum-network/src/tests/scripts/forum/forum8.test.js
+++ b/forum-network/src/tests/scripts/forum/forum8.test.js
@@ -1,6 +1,6 @@
 import { mochaRun } from '../../../util/helpers.js';
 import { INCINERATOR_ADDRESS } from '../../../util/constants.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/forum/forum9.test.js b/forum-network/src/tests/scripts/forum/forum9.test.js
index 8fbbf02..76eaf41 100644
--- a/forum-network/src/tests/scripts/forum/forum9.test.js
+++ b/forum-network/src/tests/scripts/forum/forum9.test.js
@@ -1,6 +1,6 @@
 import { mochaRun } from '../../../util/helpers.js';
 import { INCINERATOR_ADDRESS } from '../../../util/constants.js';
-import { ForumTest } from './forum.test-util.js';
+import { ForumTest } from '../forum.test-util.js';
 
 describe('Forum', function tests() {
   this.timeout(0);
diff --git a/forum-network/src/tests/scripts/input.test.js b/forum-network/src/tests/scripts/input.test.js
new file mode 100644
index 0000000..46e286d
--- /dev/null
+++ b/forum-network/src/tests/scripts/input.test.js
@@ -0,0 +1,35 @@
+import { Box } from '../../classes/display/box.js';
+// import { Document } from '../../classes/display/document.js';
+import { Scene } from '../../classes/display/scene.js';
+import { mochaRun } from '../../util/helpers.js';
+
+const rootElement = document.getElementById('scene');
+const rootBox = new Box('rootBox', rootElement).flex();
+const scene = window.scene = new Scene('Input test', rootBox);
+
+scene.withDocument();
+
+describe('Document', () => {
+  it('Exists', () => {
+    scene.withDocument('Document', (doc) => doc.remarks('Hello'));
+  });
+
+  describe('Input', () => {
+    it('Accepts input', () => {
+      scene.withDocument('Document', (doc) => doc.form());
+      const doc = scene.lastDocument;
+      const form1 = doc.lastElement;
+      const dvMap = new Map();
+      const updateFieldValueDisplay = ({ name, value }) => {
+        const dv = dvMap.get(name) ?? scene.addDisplayValue(name);
+        dvMap.set(name, dv);
+        dv.set(value);
+      };
+
+      form1.textField({ id: 'input1', name: 'Input 1', cb: updateFieldValueDisplay });
+      doc.remarks('Hmm...!');
+    });
+  });
+});
+
+mochaRun();