FEAT: Implemented CLI Gateway skill and interactive chat client
This commit is contained in:
57
docs/ux.org
Normal file
57
docs/ux.org
Normal file
@@ -0,0 +1,57 @@
|
||||
#+TITLE: User Experience (UX) Journey
|
||||
#+AUTHOR: Amr
|
||||
#+FILETAGS: :ux:design:psf:
|
||||
#+STARTUP: content
|
||||
|
||||
* Overview
|
||||
This document traces the intended User Experience (UX) journey for the ~org-agent~. It serves as a living design document to ensure that architectural decisions align with a frictionless, sovereign, and intuitive user interaction model.
|
||||
|
||||
* 1. The Zero-to-One Experience (Onboarding)
|
||||
** Goal
|
||||
A user should be able to go from discovering the project to having a running, calibrated agent in under 3 minutes, with zero prerequisite knowledge of Lisp.
|
||||
|
||||
** The Appliance Paradigm (Primary Path)
|
||||
The user runs a single command in their terminal:
|
||||
#+begin_src bash
|
||||
curl -fsSL https://raw.githubusercontent.com/gharbeia/org-agent/main/scripts/install.sh | bash
|
||||
#+end_src
|
||||
|
||||
** The Interactive Wizard
|
||||
The script verifies Docker presence and then launches an interactive prompt before booting the container:
|
||||
1. *Identity:* "What is your name?" -> Configures ~$MEMEX_USER~
|
||||
2. *Assistant:* "What shall we name your Assistant?" -> Configures ~$MEMEX_ASSISTANT~
|
||||
3. *Neural Provider:* "Select your primary neural provider [Gemini/OpenRouter/Anthropic/OpenAI]" -> Configures API Keys.
|
||||
4. *Data Gravity:* "Where is your Memex located?" -> Maps the host directory to the Docker container.
|
||||
|
||||
*Outcome:* The `.env` is generated, core skills are seeded into the user's Memex, and `docker-compose up -d` launches the daemon in the background. The user sees: /"Booting your sovereign brain in the background..."/
|
||||
|
||||
* 2. The First Contact (The CLI Gateway)
|
||||
** Goal
|
||||
Immediately after boot, the user needs a way to verify the agent is alive and capable of answering questions about their Memex without configuring complex third-party integrations (like Telegram bots).
|
||||
|
||||
** The Interaction
|
||||
The user types a local client command to connect to the background daemon:
|
||||
#+begin_src bash
|
||||
org-agent chat
|
||||
#+end_src
|
||||
|
||||
This opens a slick, colorful interactive terminal session:
|
||||
#+begin_example
|
||||
> User: Hello, what are my active projects?
|
||||
> Agent: [Thinking...]
|
||||
> Agent: You currently have 3 active projects:
|
||||
> 1. Org-agent v1.0
|
||||
> 2. Home Renovation
|
||||
> 3. Read 'The Sovereign Individual'
|
||||
#+end_example
|
||||
|
||||
** Behind the Scenes
|
||||
1. The ~org-agent chat~ client connects to the daemon's local port (e.g., 9105).
|
||||
2. It sends a ~:chat-message~ signal.
|
||||
3. The core harness routes this to the Probabilistic Engine.
|
||||
4. The Context Manager retrieves active projects from the Memex AST.
|
||||
5. The Deterministic Engine (Bouncer) verifies it is a safe read-only action.
|
||||
6. The ~:cli~ Actuator formats the Lisp response into Markdown and sends it back over the socket.
|
||||
|
||||
* 3. The Continuous Loop (Daily Usage)
|
||||
(To be defined as the agent's capabilities expand into Scribe, Gardener, and Emacs-native interactions).
|
||||
17
scripts/org-agent-chat.sh
Executable file
17
scripts/org-agent-chat.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# org-agent-chat: The terminal mouthpiece for the Sovereign Brain.
|
||||
PORT=9105
|
||||
HOST=${1:-localhost}
|
||||
|
||||
echo "Connecting to org-agent at $HOST:$PORT..."
|
||||
echo "Type your message and press Enter. Ctrl+C to exit."
|
||||
echo "--------------------------------------------------"
|
||||
|
||||
# Uses netcat (nc) for a simple bidirectional pipe.
|
||||
# Requires an open connection. We use a simple loop for persistence.
|
||||
while true; do
|
||||
read -p "User: " MESSAGE
|
||||
if [ -z "$MESSAGE" ]; then continue; fi
|
||||
# Send message and wait for one line of response from Agent
|
||||
echo "$MESSAGE" | nc -N $HOST $PORT
|
||||
done
|
||||
@@ -124,6 +124,7 @@ The Chat skill acts as the conversational UI. Because the ~org-agent~ kernel eva
|
||||
(:telegram (format nil "- To reply via Telegram: (:type :REQUEST :target :telegram :chat-id \"~a\" :text \"<Response>\")" chat-id))
|
||||
(:signal (format nil "- To reply via Signal: (:type :REQUEST :target :signal :chat-id \"~a\" :text \"<Response>\")" chat-id))
|
||||
(:matrix (format nil "- To reply via Matrix: (:type :REQUEST :target :matrix :room-id \"~a\" :text \"<Response>\")" chat-id))
|
||||
(:cli (format nil "- To reply via CLI: (:type :REQUEST :target :cli :text \"<Response>\")"))
|
||||
(t "- To reply via Emacs: (:type :REQUEST :target :emacs :action :insert-at-end :buffer \"*org-agent-chat*\" :text \"* <Response>\")"))))
|
||||
(ask-probabilistic trimmed-text :system-prompt (concatenate 'string
|
||||
"ACTUATOR IDENTITY: You are the pure Lisp actuator for the org-agent kernel.
|
||||
|
||||
148
skills/org-skill-cli-gateway.org
Normal file
148
skills/org-skill-cli-gateway.org
Normal file
@@ -0,0 +1,148 @@
|
||||
:PROPERTIES:
|
||||
:ID: cli-gateway-skill
|
||||
:CREATED: [2026-04-13 Mon 17:00]
|
||||
:END:
|
||||
#+TITLE: SKILL: CLI Gateway (Universal Literate Note)
|
||||
#+STARTUP: content
|
||||
#+FILETAGS: :gateway:cli:io:psf:
|
||||
|
||||
* Overview
|
||||
The *CLI Gateway* is the primary interaction point for the Org-Agent MVP. It provides a lightweight TCP socket server that allows local terminal clients to communicate with the daemon. It ensures a frictionless "First Contact" experience immediately following installation.
|
||||
|
||||
* Phase A: Demand (PRD)
|
||||
:PROPERTIES:
|
||||
:STATUS: SIGNED
|
||||
:END:
|
||||
|
||||
** 1. Purpose
|
||||
Provide a secure, local, and low-latency terminal interface for the Org-Agent.
|
||||
|
||||
** 2. Success Criteria
|
||||
- [X] *Ingress:* Accept plain-text messages over TCP port 9105.
|
||||
- [X] *Normalisation:* Inject messages into the harness as `:chat-message` signals.
|
||||
- [X] *Egress:* Implement the `:cli` actuator to route agent responses back to the correct client socket.
|
||||
- [X] *Client:* Provide a standalone client script for the user's host machine.
|
||||
|
||||
* Phase B: Blueprint (PROTOCOL)
|
||||
:PROPERTIES:
|
||||
:STATUS: SIGNED
|
||||
:END:
|
||||
|
||||
** 1. Architectural Intent
|
||||
The gateway runs a multi-threaded TCP server. Each connection is handled in its own thread. Inbound lines are wrapped in a Signal and processed. The `:cli` actuator retrieves the `:reply-stream` from the signal context to send the response back to the specific connected client.
|
||||
|
||||
** 2. Semantic Interfaces
|
||||
- Inbound: `(:sensor :chat-message :channel :cli :text "...")`
|
||||
- Outbound: `(:type :REQUEST :target :cli :text "...")`
|
||||
|
||||
* Phase D: Build (Implementation)
|
||||
|
||||
** Package Context
|
||||
#+begin_src lisp
|
||||
(in-package :org-agent)
|
||||
#+end_src
|
||||
|
||||
** State: Server Control
|
||||
#+begin_src lisp
|
||||
(defvar *cli-server-thread* nil)
|
||||
(defvar *cli-server-socket* nil)
|
||||
(defvar *cli-port* 9105)
|
||||
#+end_src
|
||||
|
||||
** Actuator: CLI Response
|
||||
The CLI actuator writes the agent's response back to the client's network stream. It applies a simple "Agent: " prefix for clarity.
|
||||
|
||||
#+begin_src lisp
|
||||
(defun execute-cli-action (action context)
|
||||
"Sends a message back to the connected CLI client via its network stream."
|
||||
(let* ((payload (getf action :payload))
|
||||
(text (or (getf payload :text) (getf action :text)))
|
||||
(stream (getf context :reply-stream)))
|
||||
(if (and stream (open-stream-p stream))
|
||||
(progn
|
||||
(format stream "Agent: ~a~%" text)
|
||||
(finish-output stream))
|
||||
(harness-log "CLI ERROR: No active reply stream for signal."))))
|
||||
#+end_src
|
||||
|
||||
** Server: Client Handler
|
||||
Handles an individual TCP connection. It reads lines until the connection is closed.
|
||||
|
||||
#+begin_src lisp
|
||||
(defun handle-cli-client (stream)
|
||||
"Reads lines from a CLI client and injects them as stimuli."
|
||||
(handler-case
|
||||
(loop for line = (read-line stream nil nil)
|
||||
while line do
|
||||
(let ((trimmed (string-trim '(#\Space #\Tab #\Newline #\Return) line)))
|
||||
(when (> (length trimmed) 0)
|
||||
(harness-log "CLI: Received input -> ~a" trimmed)
|
||||
(inject-stimulus (list :type :EVENT
|
||||
:payload (list :sensor :chat-message
|
||||
:channel :cli
|
||||
:text trimmed))
|
||||
:stream stream))))
|
||||
(error (c) (harness-log "CLI CLIENT ERROR: ~a" c))))
|
||||
#+end_src
|
||||
|
||||
** Server: Main Loop
|
||||
Listens for new TCP connections on the configured port.
|
||||
|
||||
#+begin_src lisp
|
||||
(defun start-cli-gateway (&optional (port *cli-port*))
|
||||
"Starts the TCP listener for local CLI clients."
|
||||
(setf *cli-server-socket* (usocket:socket-listen "0.0.0.0" port :reuse-address t))
|
||||
(setf *cli-server-thread*
|
||||
(bt:make-thread
|
||||
(lambda ()
|
||||
(unwind-protect
|
||||
(loop
|
||||
(let* ((socket (usocket:socket-accept *cli-server-socket*))
|
||||
(stream (usocket:socket-stream socket)))
|
||||
(bt:make-thread (lambda ()
|
||||
(unwind-protect (handle-cli-client stream)
|
||||
(usocket:socket-close socket)))
|
||||
:name "org-agent-cli-client-handler")))
|
||||
(usocket:socket-close *cli-server-socket*)))
|
||||
:name "org-agent-cli-gateway"))
|
||||
(harness-log "CLI: Gateway listening on port ~a" port))
|
||||
#+end_src
|
||||
|
||||
** Registration
|
||||
#+begin_src lisp
|
||||
(register-actuator :cli #'execute-cli-action)
|
||||
|
||||
(defskill :skill-gateway-cli
|
||||
:priority 200
|
||||
:trigger (lambda (ctx) (declare (ignore ctx)) nil)
|
||||
:probabilistic nil
|
||||
:deterministic (lambda (action ctx) (declare (ignore ctx)) action))
|
||||
#+end_src
|
||||
|
||||
** Initialization
|
||||
#+begin_src lisp
|
||||
(start-cli-gateway)
|
||||
#+end_src
|
||||
|
||||
* Phase E: The Client (Scripts)
|
||||
We tangle a lightweight client script that the user can run on their host machine.
|
||||
|
||||
** The Bash Client
|
||||
#+begin_src bash :tangle ../scripts/org-agent-chat.sh :shebang "#!/bin/bash"
|
||||
# org-agent-chat: The terminal mouthpiece for the Sovereign Brain.
|
||||
PORT=9105
|
||||
HOST=${1:-localhost}
|
||||
|
||||
echo "Connecting to org-agent at $HOST:$PORT..."
|
||||
echo "Type your message and press Enter. Ctrl+C to exit."
|
||||
echo "--------------------------------------------------"
|
||||
|
||||
# Uses netcat (nc) for a simple bidirectional pipe.
|
||||
# Requires an open connection. We use a simple loop for persistence.
|
||||
while true; do
|
||||
read -p "User: " MESSAGE
|
||||
if [ -z "$MESSAGE" ]; then continue; fi
|
||||
# Send message and wait for one line of response from Agent
|
||||
echo "$MESSAGE" | nc -N $HOST $PORT
|
||||
done
|
||||
#+end_src
|
||||
Reference in New Issue
Block a user