tinystruct/smalltalk is an instant messenger, and the name is the first thing to sort out
A tinystruct-based chat module which integrated with @OpenAI GPT-4 / 3.5-turbo / ChatGPT. @tinystruct
At a glance
- What is it?
- A Java chat application built on the tinystruct framework, with document question answering layered on top using SQLite, Tika and OpenAI embeddings. Nothing here is the Smalltalk language, and the README mixes three different products into one page.
- Who is it for?
- Smalltalk is a small, complete and genuinely runnable Java application: clone it, compile with the bundled Maven wrapper, and you have either a CLI chat loop or an HTTP server on port 777. Two things to know before you read too much of the README.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 57 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the project is, and what the name suggests
The README opens with two sentences that define the whole product: smalltalk is a tinystruct-based project that provides instant messaging functionality, allowing users to send text and share images, documents and other content, and it lets users interact with ChatGPT through a command line interface or a web interface.
That is an instant messenger with an LLM bolted on, not a Smalltalk implementation. The collision is real and worth flagging for anyone who finds this repository by searching for the language, since the repository metadata description repeats it: a tinystruct-based chat module which integrated with OpenAI GPT-4, 3.5-turbo and ChatGPT.
The topics list widens the frame further, including deepseek and deepseek-r1 and deepseek-v3 alongside the gpt-4 and gpt-3-5-turbo entries, which suggests the model layer is meant to be swappable even though the README only ever names OpenAI. The README has a version skew of its own, with two separate sections both titled Usage, the first covering CLI and web modes and a later one covering document upload.
The repository is small enough to read in full. Alongside the Maven wrapper files and pom.xml there is a Procfile, a system.properties file, a robot.txt, a .travis.yml, a Dockerfile, a bin directory and scripts, plus two screenshots at the root named screenshot.png and screenshot-web.png.
Install is a clone, a JDK and the bundled Maven wrapper
The installation section is a numbered list and it is honest about the order. Download the ZIP or clone the repository, install JDK 11 or newer following the OpenJDK instructions, and optionally install Eclipse or IntelliJ IDEA.
git clone https://github.com/tinystruct/smalltalk.git There is a specific accommodation for people on an older JDK.
bin/openjdk-upgradeThat single script line is worth noting because it is the only tooling the project ships for its own environment problems. If you are on JDK 8, the repository contains a script that upgrades it for you, which is convenient and also a signal about who this is for.
The key configuration is one property. Go to src/main/resources/application.properties and update openai.api_key with your own key, or set the OPENAI_API_KEY environment variable. The environment variable route matters for the container case later, where passing a key on the docker command line is the documented approach.
The last installation step is compiling with the wrapper rather than a system Maven.
./mvnw compileUsing mvnw rather than mvn means the build takes its Maven version from the .mvn directory in the repository, which is the right call for reproducibility and removes a class of version mismatch problems before you start.
One dispatcher binary, four ways to run it
The runtime is a single script called dispatcher, and it serves both the CLI and the server modes. The CLI section starts with a version check and a help listing.
bin/dispatcher --versionbin/dispatcher --helpThen the chat command starts the interactive loop.
bin/dispatcher chatThe web mode is where the deployment options diverge, and this is the part of the README that most needs reading carefully, because the three options it gives are not equivalent. The first runs the application in a servlet container, and the command uses the Tomcat import with a server port of 777.
sudo bin/dispatcher start --import org.tinystruct.system.TomcatServer --server-port 777The second runs on Netty instead.
sudo bin/dispatcher start --import org.tinystruct.system.NettyHttpServer --server-port 777The third is the container route, and the image name here does not match the repository owner.
docker run -d -p 777:777 -e "OPENAI_API_KEY=[YOUR-OPENAI-API-KEY]" -e "STABILITY_API_KEY=[YOUR-STABILITY-API-KEY]" m0ver/smalltalkTwo observations. The image is m0ver/smalltalk while the repository lives under the tinystruct organisation, so the published image comes from elsewhere and you are trusting a third party's build. And that command passes a STABILITY_API_KEY environment variable, which the README never explains anywhere, while every other configuration note mentions only OpenAI. The environment variable is optional in practice, but its presence in the documented command implies an image capability the text does not describe.
Whichever route you take, the app is then at http://localhost:777/?q=talk, and to talk to the model you type @ChatGPT into the topic of the conversation when you set it up. The model is addressed through the topic rather than through a separate interface, which is a small design decision with a real consequence: the same conversation space handles human and model participants.
The SQLite schema reveals what the RAG half actually stores
The database schema section is the most informative part of the README, because it shows the retrieval design without describing it.
CREATE TABLE document_fragments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
document_id VARCHAR(36) NOT NULL,
content TEXT NOT NULL,
fragment_index INTEGER NOT NULL,
file_path VARCHAR(255),
mime_type VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);Three tables, and each one answers a question about the implementation. document_fragments holds the split document with a document_id, a fragment_index for ordering, the source file path and the MIME type, which means the system keeps provenance all the way down to individual fragments and knows what kind of file each came from. document_embeddings stores the vector as a BLOB with an explicit embedding_dimension column, so the dimension is recorded rather than inferred, which is what you need in order to detect a model change that invalidates stored vectors.
CREATE TABLE chat_history (The chat table is keyed on meeting_code and carries user_name, message, session_id, message_type and image_url, with created_at as a DATE rather than a TIMESTAMP. A DATE for chat history in a messenger is a coarse choice: you cannot order two messages in the same day by the database alone, so ordering has to come from the insertion id or from application logic.
The absence of a vector index is also informative. With SQLite as the store and a BLOB column for embeddings, the nearest neighbour search is either brute force in Java or delegated to something else entirely. For a document question answering feature scoped to what one user has uploaded, that is a defensible trade; for a shared corpus it would not be.
Fragments go into the system prompt, not into a citation
The document question answering flow is described in four bullets: when a user uploads a document it is automatically processed, when a user asks a question the system searches for relevant document fragments, the retrieved fragments are included in the system prompt to provide context, and the AI can reference the specific document when answering.
The third bullet is the design decision worth arguing about. Retrieved fragments go into the system prompt rather than into a message, which means the retrieved text sits in the highest priority position the API offers and ahead of the user's own turn. That has the benefit of making the context hard to ignore, and the cost that everything retrieved is treated as instruction-shaped text. A fragment containing imperative language is, in that arrangement, indistinguishable from a system instruction. Any document ingestion pipeline that assembles context this way is one adversarial document away from a problem, so treat the upload feature as trusted input only.
Supported file types are broader than a chat app needs, which is the point of the feature. Plain text, Markdown, PDF, Word in both docx and doc, Excel in xlsx and xls, PowerPoint in pptx and ppt, and other text based files.
The extraction library is named in the dependencies section as Apache Tika at version 3.1.0, with SQLite for storage, the OpenAI API for generating embeddings, and tinystruct itself for the application framework and database access. Asking a question then follows a fixed four step path: convert the question to an embedding, find the most relevant fragments, include them in the context sent to the model, and return an answer that incorporates the document information. There is no mention of reranking, of chunk overlap, or of a similarity threshold, so all four of those decisions are inside the code and not documented.
Tests exist and are described without much detail
A Testing section names three entry points, which is more than most README files of this type bother with.
DocumentEmbedding.main() - Tests embedding storage and retrievalThe three are DocumentEmbedding.main() for embedding storage and retrieval, DocumentQATest for the end to end document question answering flow, and DocumentProcessor.main() for document processing and fragmentation. They are run with a batch file.
runtest.batThe script is described as initializing the SQLite database if needed, running all the test classes, and testing document processing for various file formats.
runtest.bat is the part to notice. A .bat file is a Windows batch script, and this is the only test runner the README documents, in a repository that ships a Maven wrapper, a Docker image and a Unix dispatcher script. On macOS or Linux the documented path is either running the classes by hand or invoking Maven yourself. That is a documentation gap rather than a defect, since the project clearly builds everywhere else, but it is the first friction point a new contributor will hit.
The Dockerfile confirms the Unix path works, since it compiles with the wrapper and starts the dispatcher directly.
FROM adoptopenjdk/openjdk11:alpine-nightly-slimTwo details in that image are dated. The base is an adoptopenjdk tag, and AdoptOpenJDK moved to Eclipse Temurin as the default distribution, so a nightly tag from the old project is worth checking before you rely on it. And the default command starts the plain HttpServer import on port 777 rather than the Tomcat or Netty variants the README offers, which tells you the simplest path is the intended default.
Editorial conclusion
Smalltalk is a small, complete and genuinely runnable Java application: clone it, compile with the bundled Maven wrapper, and you have either a CLI chat loop or an HTTP server on port 777. Two things to know before you read too much of the README. The name collides with the Smalltalk language, which is why the repository's own description calls itself a tinystruct-based chat module, and the deployment instructions mix three artifacts that are not the same thing, a Tomcat import, a Netty HTTP import and a Docker image published under a different name. And the licensing is inconsistent in a way that matters if you plan to build on it, since the repository metadata reports no licence while the README states Apache 2.0 in full. The document question answering half is the more interesting engineering, with a three-table SQLite schema, Tika for parsing and an explicit note that retrieved fragments go into the system prompt rather than being cited.
Frequently asked questions
Is tinystruct/smalltalk related to the Smalltalk programming language?
No. It is a Java instant messenger built on the tinystruct framework, named smalltalk, with ChatGPT interaction added as a conversation participant. The repository description calls it a tinystruct-based chat module, and the only Smalltalk connection is the name of the repository itself.
How do I run smalltalk on my machine?
Install JDK 11 or newer, clone the repository, set openai.api_key in src/main/resources/application.properties or export OPENAI_API_KEY, then compile with the bundled wrapper using ./mvnw compile. Run bin/dispatcher chat for the command line interface or start the HTTP server on port 777.
How does document question answering work in this project?
Uploads are parsed with Apache Tika, split into fragments stored in a document_fragments table with file path and MIME type, and embedded into a document_embeddings table as BLOBs with a recorded dimension. A question is embedded, the closest fragments are retrieved, and those fragments are inserted into the system prompt as context for the answer.
What database does smalltalk use?
SQLite, with three tables defined in the README: document_fragments for the split document text, document_embeddings for the vectors, and chat_history keyed on meeting_code with user name, message, session id, message type and image URL. The embedding search runs without a database level vector index.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tinystruct-smalltalk)