A simple case of kitten 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, which can be freely interleaved into C++ programs. They are being started as 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.
format
and read-char-no-hang
I previously gave an example of reading streams to their end without blocking via lispโs read-char-no-hang
.
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.
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`<h1>Kitten count</h1>
<p>${'๐ฑ'.repeat(kitten.db.numbers.count++) }
`
being somewhere between the kitten dynamic page tutorial and Kitten persistence tutorial.
Let us use this from lisp at all.
ext:run-program "kitten"
#|
(eepitch-shell)
cd ~/kittens/dynamicdb
ecl
|#
If you are not using eepitch I guess you can figure out what you would do.
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
outputECL (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: #<process TOP-LEVEL 0x7ff63765df80>.
> (locally
(declare (special *kit2way* *kitret* *kitproc*))
(multiple-value-setq
(*kit2way* *kitret* *kitproc*)
(ext:run-program "kitten" '("serve")
:wait nil)))
#<two-way stream 0x7ff635669500>
>
(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.
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)))
#<two-way stream 0x7ff634f89b40>
>
(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 codes would work.
numbers
(javascript) object to the kittendbIf 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 <database>.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
>
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))
โฌ
(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
(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
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.
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 out of kittens using the mop.
Kitten steps. What do you think (on the Mastodon thread please) about Kitten, lisp, the example interaction, the direction.
screwlisp proposes kittens