cpp-tbox: a Reactor style C++ framework for Linux services and edge devices
A complete Linux application software development tool library and runtime framework, aim at make C++ development easy.
At a glance
- What is it?
- cpp-tbox is a C++11 service-oriented development framework and component library for Linux, built on the Reactor model so a single thread owns the event loop and a thread pool absorbs the blocking work. It ships the parts application developers otherwise rewrite for every project: logging, parameter parsing, signals, a telnet shell, crash stack capture, tracing and state machines.
- Who is it for?
- cpp-tbox suits a team building a long-running Linux service or an edge device in C++ who keeps rewriting the same infrastructure layer, since the framework's value is in the logging, parameter handling, signal handling and crash capture rather than in any one networking feature.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 20 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One thread owns the event loop, the pool does the blocking work
cpp-tbox, which stands for C++ Treasure Box, is described as a service-oriented development framework and component library based on the Reactor model, aimed at making C++ development easy. The project description calls it a complete Linux application software development tool library and runtime framework.
The Reactor model is the whole architectural commitment, and the documentation points at the Node.js Reactor pattern as the reference. The main thread handles non-blocking IO events in Reactor mode, and cooperates with a ThreadPool to perform large calculations and blocking operations.
The stated benefit is about contention rather than raw speed. This mode avoids the annoyance of competing locking in multi-thread mode, and the program is stable and reliable. That is a real and underappreciated trade in C++ server work: the alternative to a single-threaded event loop is shared mutable state guarded by locks, and every lock is a place for a deadlock, a priority inversion or a subtle data race.
The target domains follow from that. The application field lists intelligent hardware such as robots including sweepers and commercial service robots, IPC, drones and vehicles; edge computing components such as smart home gateways and IoT edge gateways; and services such as SOCKS5 and middleware.
The language floor is C++11, the platform badge is Linux, and the last push was on 2026-10-03. The project has no GitHub releases, and the licence is recorded as a custom notice that GitHub cannot classify, with a LICENSE file at the root.
The audience is a C++ developer writing a service that runs for a long time on Linux and needs the plumbing to be somebody else's problem.
You write business code and register it, the framework writes the main function
The second feature in the list describes the integration model, and it is the part that determines how much of your existing code survives.
All non-business-related work is handled using the built-in main framework. The documentation is blunt about what that covers: how to output the log, how to parse the parameters, how to exit the program, and how to write the main function. The main frame is all handled for you.
What you do is derive the tbox::main::Module class, fill in the business code, and then register to the framework. That is the entire contract. There is no plugin registry, no dependency injection container and no template file to copy; there is a base class and a registration call.
That simplicity is the appeal and also the limit. A team that arrives with an existing architecture, its own dependency injection, its own configuration loading and its own logger keeps all of it and gains little from the framework, because the framework's value is precisely in replacing those pieces. The adoption decision is really a decision about whether you want the framework's opinions to win over your own on the boring parts.
The other thing worth noting is what the framework does not do. It is not a networking library in the sense of an HTTP client or a database driver, and the components table lists the modules that do exist: base for log printing and common tools, util for an accessibility module, event for IO, Timer and Signal driven events described as the heart of the whole framework, eventx for a ThreadPool, a WorkThread worker thread and a TimerPool timer pool, log for terminal, syslog and file output, and trace for outputting traces to files in real time. The network module exists as well, and the entry point in the table is cut off in the visible documentation, so the full component list is worth reading in the repository.
Three log sinks, colour coded levels and per module filtering at runtime
Logging is where the framework spends the most detail, and the detail is the useful part.
There are three sinks: stdout, which outputs the log to the terminal via std::cout; syslog, which outputs logs via syslog(); and filelog, which writes to a specified directory in the format <PRIFIX>.YYMMDD_HHMMSS.<PID>.log. If the file size exceeds 1M, a new log file is created, and because writing files is inefficient, the output channel uses a front-end and back-end mode for that path.
One or more of the three sinks can be selected in the startup parameters, and can also be changed through the terminal during operation. That second capability is the one that matters in practice, because it means you can turn on file logging on a device that is already running without restarting it.
Each log line carries a lot of context: level, time accurate to microseconds, thread number, module name, function name, text, file name and line number. Levels are distinguished by colour, and for anomalies red and yellow are used together with highlighting so they stand out.
The third piece is per module filtering. The log level can be set separately for different modules while the program is running, which is the difference between a logger you configure at build time and one you can use to isolate a subsystem on a live device. On an edge device with no debugger attached, that is worth a lot.
The related components round out the picture. The trace module records the time and duration of each execution of a marked function and can export an icicle diagram, which the documentation presents as a tool for performance analysis and for troubleshooting event blocking problems.
JSON parameters, a telnet shell and signal handling that shuts down cleanly
Three features are about the operational life of a service rather than its logic.
Parameters are provided in JSON format, and any format of running parameters can be passed in, including integers, decimals, strings, arrays and combination parameters. You can use -c your_cfg_file.json to import a configuration file in JSON format at execution time, and -s 'xx.yy.zz=vvv' to specify parameters temporarily. The configuration file also supports the include command, so a configuration can be assembled from several files.
The temporary override flag matters more than it looks. On a device fleet, the ability to change one value at launch, or better to override it without editing a file on the device, removes a whole category of deployment friction.
The shell-like terminal is the other operational feature. You can interact with the running service through telnet, make it print internal data, or perform specific actions, and the documentation says this greatly reduces the difficulty of debugging. A running service that you can interrogate over the network is a different thing from a running service you can only observe through logs.
Graceful exit is the third. On receiving SIGINT, SIGTERM, SIGQUIT or SIGPWR, the framework runs an orderly exit and releases resources, and the documentation calls this crucial for ensuring program integrity and conducting memory analysis. A service that dies on SIGTERM leaves open sockets and half written state; a service that shuts down cleanly can be restarted by a supervisor without a human intervening.
And then there is the exception capture mechanism, which the documentation describes as comprehensive. When program exceptions occur such as segment fault, assertion failure, bus error or an uncaught exception, the framework captures and prints the complete call stack into the log system. The stated effect is that you no longer look blank at a crash, and that analysing crash issues on online devices becomes very simple with basically no need to use gdb to analyse coredumps.
For a Linux service running unattended on a robot or a gateway, that is arguably the most valuable feature in the whole list, because the failure you cannot reproduce locally is the one that matters.
The build is a Makefile tree with vendored dependencies and debug defaults
The repository layout explains how the project is put together. There is a modules/ directory holding the components, a 3rd-party/ directory for vendored dependencies, tools/ and examples/ directories, a mk/ directory, and the top level build files: CMakeLists.txt, Makefile, build_env.mk, config.mk, version.mk and Config.cmake.in. The examples directory has a subdirectory per feature area, with alarm, base, dbus, event, eventx, http, jsonrpc, main, mqtt, network, run, terminal, trace and util, and its own Makefile.
The Makefile is the primary build system and it reveals the defaults clearly.
CCFLAGS := -Wall
RELEASE ?= 0
ENABLE_ASAN ?= 0
ENABLE_GPROF ?= 0So a default build is a debug build, compiled with -DDEBUG=1 -O0 -ggdb, and the release path is opted into with RELEASE=1, which switches the flags to -O2 -Os. AddressSanitizer and gprof are separate opt-in flags, with ASAN adding -fsanitize=address and -fno-omit-frame-pointer, and gprof adding -pg.
Two details in the Makefile are worth knowing. The version is compiled in as preprocessor definitions, TBOX_VERSION_MAJOR, TBOX_VERSION_MINOR and TBOX_VERSION_REVISION, taken from version.mk, so the running binary reports its own version. And the default target is not just the library: all is 3rd-party modules test tools examples, so a plain make builds the third party code, the modules, runs the tests, builds the tools and builds the examples. There is a separate run_test target that runs each module's test binary in turn.
The examples are worth building even if you never use them, because the directory listing is the map of the API surface: an http example, an mqtt example, a dbus example, a jsonrpc example, a network example and a terminal example tell you which protocols the framework has examples for, which is a faster way to scope the framework than reading the component list.
Where cpp-tbox is the wrong tool
The first wrong-tool case is a project that is not Linux only. The platform badge says Linux, the documentation says it is a complete Linux application software development tool library, and the components include syslog output and Unix signal handling. Porting it to Windows or macOS is not a configuration change.
The second case is a codebase that already has this infrastructure. A team with boost.asio, a logging library, a JSON config parser and a signal handler in house has all of the pieces cpp-tbox provides, and adopting the framework means replacing working code with the framework's opinions, including its C++11 floor, which rules out the newer standard library facilities that a modern codebase would otherwise use.
The third case is a project that needs a specific protocol or a specific scale and finds the framework stops short. It is a framework, not an ecosystem, and the components table is the boundary of what it covers. If your service needs an HTTP client with a modern TLS stack, a database driver, or an observability stack that talks OpenTelemetry, none of that is in here.
There is also a maintenance consideration that the repository does not discuss. The project has no GitHub releases, so there is no version to pin, and the last push was on 2026-10-03. A vendored 3rd-party/ directory means the dependency versions are part of the repository, so an upgrade of anything in that tree is your upgrade, and the security posture of those vendored copies is yours to track.
On licensing, the badge in the README says MIT and the Makefile header states that use of the source code is governed by the MIT license found in the LICENSE file, with the copyright held by Hevake and contributors since 2018. The project metadata records a custom licence that GitHub cannot classify, so the LICENSE file and the Makefile header are the authority here.
The last thing to weigh is the size of the commitment. This is a framework you adopt wholesale or not at all. Its value is concentrated in the parts you would otherwise write, and if you already wrote them, the framework is overhead.
Editorial conclusion
cpp-tbox suits a team building a long-running Linux service or an edge device in C++ who keeps rewriting the same infrastructure layer, since the framework's value is in the logging, parameter handling, signal handling and crash capture rather than in any one networking feature. It does not suit a cross-platform project, because the platform badge is Linux, and it does not suit a codebase that needs a standard library it already has in boost or asio, since the third party directory means the framework vendors its own dependencies. Before adopting, read the modules/ directory to see which components you would actually use, build with RELEASE=1 rather than the debug default, and check whether the C++11 floor constrains the standard library features your own code relies on.
Frequently asked questions
What is cpp-tbox?
C++ Treasure Box is a service-oriented development framework and component library based on the Reactor model, aimed at making C++ development easy on Linux. The main thread handles non-blocking IO events and cooperates with a ThreadPool for large calculations and blocking operations.
How do I write an application with cpp-tbox?
You derive the tbox::main::Module class, fill in the business code and register to the framework. The built-in main framework handles the non-business work such as logging, parameter parsing and program exit.
What log destinations does cpp-tbox support?
Three sinks: stdout through std::cout, syslog through syslog(), and a file log written to a specified directory as <PRIFIX>.YYMMDD_HHMMSS.<PID>.log, rolling over when the file exceeds 1M. Sinks are selected at startup and can also be changed through the terminal while running, and the log level can be set per module at runtime.
How do I build cpp-tbox for production?
The Makefile defaults to a debug build, so you set RELEASE=1 to compile with -O2 -Os instead of -DDEBUG=1 -O0 -ggdb. AddressSanitizer and gprof are separate opt-in flags, ENABLE_ASAN=1 and ENABLE_GPROF=1, and the default all target builds the third party code, the modules, the tests, the tools and the examples.
What license is cpp-tbox released under?
The README badge and the Makefile header state that use of the source code is governed by the MIT license in the LICENSE file, with copyright held by Hevake and contributors since 2018, though the project metadata records a custom licence that GitHub cannot classify.
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/cpp-main-cpp-tbox)Was this useful?