--- layout: ../Site.layout.js --- # Interactive host / visitor kitten live kittendb interaction in embeddable common lisp A simple case of [kitten](https://kitten.small-web.org/) server .. kitten visitor interaction is where each kitten pageload increases the number of kittens on the page by one, and the kitten server operator can both read, and arbitrarily change this number live (for the next page load). In practice, different tls authenticated kitten visitors will get different abilities, but to start with, the host and the visitor can interact through kitten's database via kitten's dynamic page generation as you are reading here. For this example, I am running Kitten's `kitten serve` and `kitten shell` from inside of [embeddable common lisp](https://ecl.common-lisp.dev/), which can be freely interleaved into C++ programs. They are being started as [external processes](https://ecl.common-lisp.dev/static/manual/Operating-System-Interface.html#External-processes), and communicated with textually. `kitten shell` uses an (offline javascript) nodejs base. I refered to turning-C++-programs-into-kittens as my [insane kitten fairy godmother theory](/momentary/screwlisps-cl-kitten-future-theory/). ## Lisp `format` and `read-char-no-hang` I [previously gave an example of reading streams to their end without blocking](/programming/embeddable-common-lisp-external-process-multi-processing-eg/) via [lisp's `read-char-no-hang`](https://www.lispworks.com/reference/HyperSpec/Body/f_rd_c_1.htm). Here also, I am sending strings to the `kitten shell` via common lisp's format. If you are not using embeddable common lisp, you can send the kitten/shell commands directly to your shell somehow else. `(format stream "~a~%" "foo")` sends `foo` to `stream` stream. ## Kitten In `#P"~/kittens/dynamicdb/"` I have the following ### `#P"index.page.js"` ``` if (kitten.db.numbers === undefined) kitten.db.numbers = { count: 2 }; export default () => kitten.html`

Kitten count

${'๐Ÿฑ'.repeat(kitten.db.numbers.count++) } ` ``` being somewhere between the [kitten dynamic page tutorial](https://kitten.small-web.org/tutorials/dynamic-pages/) and [Kitten persistence tutorial](https://kitten.small-web.org/tutorials/persistence). Let us use this from lisp at all. ## Embeddable common lisp `ext:run-program "kitten"` ### Setup ``` #|  (eepitch-shell) cd ~/kittens/dynamicdb ecl |# ``` If you are not using *eepitch* I guess you can figure out what you would do. ## Run Kitten inside of ecl - `kitten serve` Noting we `cd`(1)'d into our directory already, let's use embeddable common lisp's `ext:run-program` to just start serving the kitten. ``` (locally (declare (special *kit2way* *kitret* *kitproc*)) (multiple-value-setq (*kit2way* *kitret* *kitproc*) (ext:run-program "kitten" '("serve") :wait nil))) (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *kit2way*)) :while ch :do (princ ch)) ``` ### `kitten serve` output ``` ECL (Embeddable Common-Lisp) 21.2.1 (git:UNKNOWN) Copyright (C) 1984 Taiichi Yuasa and Masami Hagiya Copyright (C) 1993 Giuseppe Attardi Copyright (C) 2013 Juan J. Garcia-Ripoll Copyright (C) 2018 Daniel Kochmanski Copyright (C) 2021 Daniel Kochmanski and Marius Gerbershagen ECL is free software, and you are welcome to redistribute it under certain conditions; see file 'Copyright' for details. Type :h for Help. Top level in: #. > (locally (declare (special *kit2way* *kitret* *kitproc*)) (multiple-value-setq (*kit2way* *kitret* *kitproc*) (ext:run-program "kitten" '("serve") :wait nil))) # > (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *kit2way*)) :while ch :do (princ ch)) ๐Ÿฑ Kitten by ]8;;https://ar.alAral Balkan]8;;, ]8;;https://small-tech.orgSmall Technology Foundation]8;; Version 0-046649-22.11.0-20250502014448 Born 2025/05/02 at 01:44:48 UTC (Taurus) Fav. colour #046649 โ–ˆโ–ˆโ–ˆ API version 0 Runtime Node.js 22.11.0 โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚ Like this? Fund us! โ”‚ โ”‚ โ”‚ โ”‚ Weโ€™re a tiny, independent not-for-profit. โ”‚ โ”‚ ]8;;https://small-tech.org/fund-ushttps://small-tech.org/fund-us]8;; โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ Need help? ]8;;https://kitten.small-web.org/tutorials/Tutorials]8;; โ€ข ]8;;https://kitten.small-web.org/reference/Reference]8;; โ€ข ]8;;https://codeberg.org/kitten/app/issuesIssues]8;; domainsIncludingRedirectedOnes [ 'localhost' ] ๐ŸŒ Domain ]8;;https://localhosthttps://localhost ]8;;๐Ÿ“‚ Source ]8;;file:///home/me/kittens/dynamicdb๐Ÿ /kittens/dynamicdb]8;; ๐Ÿ’พ Data ]8;;/home/me/.local/share/small-tech.org/kitten/data/home.me.kittens.dynamicdb.localhost.443Open app data folder]8;; โ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œ ๐Ÿ”’ Donโ€™t forget to create your identity ]8;;https://localhost/๐Ÿ’•/hello/probably-dont-share/One-time use identity creation link]8;; โ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œโ•Œ Server is running and listening for connectionsโ€ฆ ๐Ÿข Interactive shell is available on 127.0.0.1, port 1337. ๐Ÿข To access it, run kitten shell. NIL > ``` Okay! It seems like our kitten is being served. However, the ansi escape codes are just printing, but the kittencode characters are great. ## Start a `kitten shell` as described ``` (locally (declare (special *2way* *ret* *proc*)) (multiple-value-setq (*2way* *ret* *proc*) (ext:run-program "kitten" '("shell") :wait nil))) (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *2way*)) :while ch :do (princ ch)) ``` โฌ‡ ``` > (locally (declare (special *2way* *ret* *proc*)) (multiple-value-setq (*2way* *ret* *proc*) (ext:run-program "kitten" '("shell") :wait nil))) # > (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *2way*)) :while ch :do (princ ch)) ๐Ÿฑ Kitten by ]8;;https://ar.alAral Balkan]8;;, ]8;;https://small-tech.orgSmall Technology Foundation]8;; Version 0-046649-22.11.0-20250502014448 Born 2025/05/02 at 01:44:48 UTC (Taurus) Fav. colour #046649 โ–ˆโ–ˆโ–ˆ API version 0 Runtime Node.js 22.11.0 โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚ Like this? Fund us! โ”‚ โ”‚ โ”‚ โ”‚ Weโ€™re a tiny, independent not-for-profit. โ”‚ โ”‚ ]8;;https://small-tech.org/fund-ushttps://small-tech.org/fund-us]8;; โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ Need help? ]8;;https://kitten.small-web.org/tutorials/Tutorials]8;; โ€ข ]8;;https://kitten.small-web.org/reference/Reference]8;; โ€ข ]8;;https://codeberg.org/kitten/app/issuesIssues]8;; ๐Ÿฑ ๐Ÿ’ฌ (127.0.0.1:41028) NIL > ``` I guess if we were in a term those [ANSI terminal escape](https://en.wikipedia.org/wiki/ANSI_escape_code) codes would work. ### Add a `numbers` (javascript) object to the kittendb If *you have visited* the page, the kitten's page generation will have populated this already. If *not* it will not exist yet. It is not a problem to attempt to run this and fail in the `kitten shell`. ``` (format (two-way-stream-output-stream *2way*) "~a~%" "kitten.db.numbers = { count: 3 }") (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *2way*)) :while ch :do (princ ch)) ``` โฌ‡ ``` > (format (two-way-stream-output-stream *2way*) "~a~%" "kitten.db.numbers = { count: 3 }") NIL > (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *2way*)) :while ch :do (princ ch)) kitten.db.numbers = { count: 3 } Uncaught: Error: Table numbers already exists. To replace it, please first call await .numbers.__table__.delete(). at _JSDB.setHandler (file:///home/me/.local/share/small-tech.org/kitten/app/kitten-bundle.js:243715:15) ๐Ÿฑ ๐Ÿ’ฌ (127.0.0.1:41028) NIL > ``` ### Read the `kittendb` current count ``` (format (two-way-stream-output-stream *2way*) "~a~%" "kitten.db.numbers.count") (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *2way*)) :while ch :do (princ ch)) ``` โฌ‡ ``` ``` ### (Interactively) set a new value in the kittendb object ``` (format (two-way-stream-output-stream *2way*) "~a~%" "kitten.db.numbers.count = 1") (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *2way*)) :while ch :do (princ ch)) ``` โฌ‡ ``` > (format (two-way-stream-output-stream *2way*) "~a~%" "kitten.db.numbers.count = 1") NIL > (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *2way*)) :while ch :do (princ ch)) kitten.db.numbers.count = 1 1 ๐Ÿฑ ๐Ÿ’ฌ (127.0.0.1:41028) NIL ``` ### Get kittendb value ``` (format (two-way-stream-output-stream *2way*) "~a~%" "kitten.db.numbers.count") (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *2way*)) :while ch :do (princ ch)) ``` โฌ‡ ``` > (format (two-way-stream-output-stream *2way*) "~a~%" "kitten.db.numbers.count") NIL > (loop :for ch := (read-char-no-hang (two-way-stream-input-stream *2way*)) :while ch :do (princ ch)) kitten.db.numbers.count 1 ๐Ÿฑ ๐Ÿ’ฌ (127.0.0.1:41028) NIL ``` ### Killing the kitten Unfortunate heading aside. ``` (format (two-way-stream-output-stream *2way*) "~a~%" "process.kill(0)") ``` This seems to end up suddenly killing the whole process for me, after which I might as well ``` #|  (eepitch-kill) |# ``` for good measure. # Conclusions Simple host-visitor communication is seen via the visitor hitting a kitten and the host reading and changing the number of kittens on the kittenloads interactively, live in response. In practice, the host will be a robot system connecting two visitors' interactions (visitor + host๐Ÿค– + visitor), but this article showed one-half of the dynamic in interactive practice (host + visitor) My model for kittens in lisp is to make an [elephant](https://common-lisp.net/project/elephant) out of [kittens using the mop](https://screwlisp.small-web.org/kitten/planning-cl-kitten-mop/). # Fin. Kitten steps. What do you think [(on the Mastodon thread please)](https://gamerplus.org/@screwlisp/114708184726530511) about Kitten, lisp, the example interaction, the direction.