README-work
Chatnik
Raku package that provides Command Line Interface (CLI) scripts for conversing with persistent Large Language Model (LLM) personas.
"Chatnik" uses files of the host Operating System (OS) to maintain persistent interaction with multiple LLM chat objects.
"Chatnik" can be seen as a package that "moves" the LLM-chat objects interaction system of the Raku package "Jupyter::Chatbook", [AAp3], into typical OS shell interaction. (I.e. an OS shell is used instead of a Jupyter notebook.)
There are several consequences of this approach:
Multiple LLMs and LLM providers can be used
The chat messages can use the provided by the package "LLM::Prompts", [AAp2]:
Prompts collection
Prompt spec DSL and related prompt expansion
Easy access to OS shell functionalities
Remark: The package "LLM::DWIM", [BDp1], is very similar in spirit to "Chatnik". "LLM::DWIM" does not use prompt expansion, uses only one chat object, and, although it saves chat history, it does not create chat objects with that history. Both packages are based on the LLM packages "LLM::Functions", [AAp1], and "LLM::Prompts", [AAp2].
Installation
From Zef Ecosystem:
zef install ChatnikFrom GitHub:
zef install https://github.com/antononcube/Raku-Chatnik.gitLLM access setup
There are several options for using LLMs with this package:
Install and run Ollama
For the corresponding setup see "WWW::Ollama"
Run a llamafile / LLaMA model
For the corresponding setup see "WWW::LLaMA"
Have programmatic access to LLMs of service providers like OpenAI or Gemini
For the corresponding setup see "WWWW::OpenAI", "WWWW::Gemini", or "WWW::MistralAI"
Basic usage examples
The prompts used in the examples are provided by the Raku package "LLM::Prompts", [AAp2]. Since many of the prompts of that package have dedicated pages at the Wolfram Prompt Repository (WPR) the examples use WPR reference links.
A few turns chat
The script llm-chat is used to create and chat with LLM personas (chat objects):
Create and chat with an LLM persona named "yoda1" (using the Yoda chat persona):
llm-chat -i=yoda1 --prompt=@Yoda hi who are youContinue the conversation with "yoda1":
llm-chat -i=yoda1 since when do you use a green light saberRemark: The message input for llm-chat can be given in quotes. For example: llm-chat 'Hi, again!' -i=yoda1.
Remark: The script chatnik can be used instead of llm-chat.
Apply prompt(s) to shell pipeline output
Summarize a file using the prompt "Summarize":
cat README.md | llm-chat --prompt=@SummarizeSummarize a file and then translate it to another language using the prompt "Translate":
cat README.md | llm-chat --prompt=@Summarize | llm-chat -i=rt --prompt='!Translate|Russian'Remark: The second llm-chat invocation has to use different chat object identifier because the default
chat object, with identifier "NONE", is already primed with the prompt "Summary".
Chat objects management
The CLI script llm-chat-meta can be used to view and manage the chat objects used by "Chatnik".
Here is its usage message:
llm-chat-meta --helpList all chat objects ("chats" and "personas" are synonyms to "list"):
llm-chat-meta list --format=jsonHere we see the messages of "yoda1":
llm-chat-meta messages -i yoda1Here we clear the messages:
llm-chat-meta clear -i yoda1Remark: Calling the script chatnik with the command meta has the same effect as llm-chat-meta.
For example, chatnik meta clear -i yoda1 can be used instead of the previous command.
Advanced usage examples
Asking for a result in specific format
llm-chat -i=beta --model=ollama::gemma3:12b 'What are the populations of the Brazilian states? #NothingElse|"JSON data frame"' Make a request, echo, and place in clipboard
llm-chat -i=unix '@CodeWriterX|Shell macOS list of files echo the result and copy to clipboard.' | tee /dev/tty | pbcopy# ls | tee >(pbcopy) Remark: Instead of ... | tee /dev/tty | pbcopy the pipeline command ... | tee >(pbcopy) can be also used.
Make a mind-map of a file
Consider the task of making an (LLM derived) mind map over a certain document. (Say, this REDME.) There are several ways to do that.
1
Put file's content to be the positional input argument
Use the prompt "MermaidDiagram" in
--prompt
llm-chat -i=mmd "$(cat README.md)" --model=ollama::gemma4:26b --prompt=@MermaidDiagram2
Put file's content to be the positional input argument
Expand the prompt "manually" via
llm-promptprovided by "LLM::Prompts", [AAp2]
llm-chat -i=mmd "$(cat README.md)" --model=ollama::gemma4:26b --prompt="$(llm-prompt 'MermaidDiagram' below)"Remark: This example shows another computation result can be used as a prompt. I.e. no need to rely on the automatic prompt expansion.
3
Give the prompt "MermaidDiagram" as input
Put file's content to be the value of
--promptPut additional prompting for further interaction
llm-chat -i=mmd @MermaidDiagram --model=ollama::gemma4:26b --prompt="FOCUS TEXT START:: $(cat README.md) ::END OF FOCUS TEXT. If it is not clear which text to use, use FOCUS TEXT."This command allows to do further tasks with the file content as context. For example:
llm-chat -i=mmd '!ThinkingHatsFeedback'Result
The commands above produce results similar to this diagram:
Render Markdown results with dedicated programs
Get feedback on a text with the prompt "ThinkingHatsFeedback":
cat README.md | llm-chat -i=th --prompt="$(llm-prompt ThinkingHatsFeedback 'the TEXT is GIVEN BELOW.' --format=Markdown)" --model=ollama::gemma4:26b Remark: By default the prompt "ThinkingHatsFeedback" gives the hat-feedback table in JSON format.
(Currently) the prompt expansion does not handle named parameters, hence,
llm-prompt is used to specify the Markdown format for that table.
Get the LLM (chat object) answer -- via llm-chat-meta -- put into a temporary file and "system open" that file:
tmpfile="$TMPDIR/llmans.md"; llm-chat-meta -i=th last-message > "$tmpfile"; open "$tmpfile"The command above works on macOS. On Linux instead of explicitly creating a file in the temporary dictory,
the argument --suffix can be passed to mktemp. For example:
tmpfile=$(mktemp --suffix=".md"); llm-chat-meta -i=th last-message > "$tmpfile"; open "$tmpfile"Tabulate the LLM personas summary
If the text browser w3m and the Raku package "Data::Translators" are installed, the following pipeline can be used to tabulate the summary the LLM personas:
llm-chat-meta list --format=json | data-translation | w3m -T text/html -dump -cols 120Customization
Default model
Default model can be specified with the env variable CHATNIK_DEFAULT_MODEL. For example:
export CHATNIK_DEFAULT_MODEL=ollama::gemma4:26bRemove with unset CHATNIK_DEFAULT_MODEL.
Pre-defined LLM personas
Use defined LLM personas are specified with JSON file with a content like this:
[
{
"chat-id": "raku",
"conf": "ChatGPT",
"prompt": "@CodeWriterX|Raku",
"model": "gpt-4o",
"max-tokens": 4096,
"temperature": 0.4
}
](See such a file here.)
The LLM personas JSON file can be specified with the OS environmental variables
CHATNIK_LLM_PERSONAS_CONF or RAKU_CHATBOOK_LLM_PERSONAS_CONF -- the former has precedence over the latter.
To load the predefined LLM personas use the command:
llm-chat-meta load-llm-personasImplementation details
Architectural design
Here is a flowchart that describes the interaction between the host Operating System and chat objects database:
Here is the corresponding UML Sequence diagram:
Persistent chat objects
Using a JSON file for keeping the chat objects database is a fairly straightforward idea. Efficiency considerations for "using the OS to manage the database" are probably can not that important because LLMs invocation is (much) slower in comparison.
Remark: The following quote is attributed to Ken Thompson about UNIX:
We have persistent objects, they're called files.
TODO
TODO Implementation
DONE Chats DB export
DONE Chats DB import
DONE LLM persona creation
DONE LLM persona repeated interaction
DONE CLI
llm-chatDONE Simple:
$input&*%argsDONE Multi-word:
@words&*%argsDONE From pipeline
CANCELED Format?
DONE CLI
llm-chat-metaDONE Commands reaction
DONE View messages for an id
DONE Clear messages for an id
DONE Delete chat for an id
DONE View all chats
DONE Delete all chats
DONE Clear message for an id by range
DONE Take message for an id by index
DONE Take last message for an id
DONE Load LLM personas in the JSON file used for initialization by "Jupyter::Chatbook"
TODO Handling images
TODO Handle image path specified with the option
--imageTODO Recognizing the input is or has an image file path
TODO Handle output of image generation models
TODO Use cases:
TODO Image generation from a textual description
TODO Extract and translate textual content of an image
TODO Make another image from a given image
TODO Unit tests
DONE Export & import
DONE Main workflow
DONE Persona repeated interaction
DONE Persona creation
TODO CLI tests
TODO Documentation
DONE Flowchart & sequence diagram
DONE Usage examples
DONE Basic examples
DONE Advanced examples
DONE Management (meta) examples
TODO Demo video
References
Articles, blog posts
[AA1] Anton Antonov, "Chatnik: LLM Host in the Shell ā Part 1: First Examples & Design Principles", (2026), RakuForPrediction at WordPress.
Packages
[AAp1] Anton Antonov, LLM::Functions, Raku package, (2023-2026), GitHub/antononcube.
[AAp2] Anton Antonov, LLM::Prompts, Raku package, (2023-2025), GitHub/antononcube.
[AAp3] Anton Antonov, Jupyter::Chatbook, Raku package, (2023-2026), GitHub/antononcube.
[BDp1] Brian Duggan, LLM::DWIM, Raku package, (2024-2025), GitHub/bduggan.
[JSp1] Jonathan Stowe, XDG::BaseDirectory, Raku package, (2016-2026), GitHub/jonathanstowe.