2026-10-14 00:01:03 +03:00
|
|
|
# Bantam: tiny, powerful, DIY AI agent (C++ port)
|
|
|
|
|
|
|
|
|
|
## About
|
|
|
|
|
|
|
|
|
|
Bantam is a minimalist, dependency-light AI agent that talks to any
|
|
|
|
|
OpenAI-compatible `/chat/completions` API. This directory is a faithful,
|
|
|
|
|
**modern C++20 port** of the pure-C reference implementation
|
|
|
|
|
(`bantam-c`), which itself tracks the Go reference implementation
|
|
|
|
|
(`main.go` + `term_*.go`, module `code.luxferre.top/luxferre/bantam`).
|
|
|
|
|
|
|
|
|
|
It provides the same agentic loop — autonomous tool execution, direct shell
|
|
|
|
|
interaction, file writing/editing, real-time response streaming, markdown
|
|
|
|
|
terminal rendering with box-drawing tables, Fibonacci backoff network
|
|
|
|
|
resilience, context-window auto-discovery, token usage tracking with prompt
|
|
|
|
|
cache breakdowns, and conversation compaction — implemented in C++20 using
|
|
|
|
|
standard, safe containers and RAII.
|
|
|
|
|
|
|
|
|
|
The terminal markdown renderer (inline styles, headings, lists, block quotes,
|
|
|
|
|
fenced code, and box-drawing tables) is implemented natively, so no external
|
|
|
|
|
Markdown library is required. Interactive line editing is handled by **GNU
|
|
|
|
|
readline**, which provides the prompt, history and Emacs-style key bindings,
|
|
|
|
|
so no hand-rolled terminal code is needed.
|
|
|
|
|
|
|
|
|
|
The whole philosophy of Bantam rests on two principles:
|
|
|
|
|
|
|
|
|
|
1. The structure must be as simple as possible for anyone to reimplement the
|
|
|
|
|
agent from a plain algorithm description.
|
|
|
|
|
2. The agent only needs a minimal set of tools: `bash` to run shell commands,
|
|
|
|
|
`read` to inspect files and directories, and `write` to write/edit files.
|
|
|
|
|
|
|
|
|
|
### Design goals relative to the C port
|
|
|
|
|
|
|
|
|
|
- Use standard, safe C++ containers (`std::string`, `std::vector`,
|
|
|
|
|
`std::map`, `std::span`) instead of raw memory areas.
|
|
|
|
|
- Eliminate hand-rolled allocation/string code; rely on RAII so there is far
|
|
|
|
|
less room for memory-allocation related vulnerabilities.
|
2026-10-14 08:36:39 +03:00
|
|
|
- Depend only on **libcurl** (HTTP) and **GNU readline** (interactive line
|
|
|
|
|
editing); JSON parsing/serialization and Markdown rendering are implemented
|
|
|
|
|
natively in C++20 with no external or vendored library bloat, and the unsafe
|
|
|
|
|
json-c C API is no longer used.
|
2026-10-14 00:01:03 +03:00
|
|
|
|
|
|
|
|
## Repository layout
|
|
|
|
|
|
|
|
|
|
```
|
2026-10-14 08:36:39 +03:00
|
|
|
bantam.hpp all shared declarations (structs, prototypes, native Json type)
|
2026-10-14 00:01:03 +03:00
|
|
|
util.cpp string building, UTF-8, prompt-injection filter, color, IDs, MD5
|
|
|
|
|
config.cpp config file parsing, env precedence, /models discovery
|
2026-10-14 08:36:39 +03:00
|
|
|
json.cpp native RFC 8259 JSON engine, request building + response parsing
|
2026-10-14 00:01:03 +03:00
|
|
|
llm.cpp libcurl HTTP client, OpenCode headers, backoff, SSE streaming
|
|
|
|
|
tools.cpp bash/read/write tools, oversized-result offloading
|
|
|
|
|
session.cpp message copy, session save/load, compaction
|
|
|
|
|
render.cpp terminal markdown renderer (native, box-drawing tables)
|
|
|
|
|
editor.cpp GNU readline line editor + history (+ term helpers)
|
|
|
|
|
main.cpp REPL, agentic loop, tool dispatch, commands
|
|
|
|
|
Makefile POSIX-compatible build
|
|
|
|
|
README.md this document
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Prerequisites
|
|
|
|
|
|
|
|
|
|
- A C++20 compiler (`c++` / `g++` / `clang++`) and a POSIX `make`
|
|
|
|
|
(`bmake`, `gmake`, `smake`, …).
|
|
|
|
|
- **libcurl** development packages, available via the standard include /
|
2026-10-14 08:36:39 +03:00
|
|
|
library search paths. The JSON layer is implemented natively in `json.cpp`
|
|
|
|
|
and needs no separate dependency.
|
2026-10-14 00:01:03 +03:00
|
|
|
- **GNU readline** development packages (`libreadline-dev` on Debian/Ubuntu,
|
|
|
|
|
`readline` on Fedora/macOS) for the interactive prompt, history and line
|
|
|
|
|
editing. On common systems:
|
|
|
|
|
```bash
|
|
|
|
|
# Debian / Ubuntu
|
|
|
|
|
apt-get install libreadline-dev
|
|
|
|
|
# Fedora / RHEL
|
|
|
|
|
dnf install readline-devel
|
|
|
|
|
# macOS (Homebrew)
|
|
|
|
|
brew install readline
|
|
|
|
|
```
|
|
|
|
|
- An OpenAI-compatible API endpoint (or an API key for one).
|
|
|
|
|
|
|
|
|
|
On common systems:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Debian / Ubuntu
|
|
|
|
|
apt-get install libcurl4-openssl-dev build-essential
|
|
|
|
|
# Fedora / RHEL
|
|
|
|
|
dnf install libcurl-devel
|
|
|
|
|
# FreeBSD
|
|
|
|
|
pkg install curl
|
|
|
|
|
# macOS (Homebrew)
|
|
|
|
|
brew install curl
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If the libcurl headers or libraries live in a non-standard prefix, override
|
|
|
|
|
them at build time, e.g.:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
make CPPFLAGS="-I/opt/include" LDLIBS="-L/opt/lib -lcurl"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Building
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-10-14 08:36:39 +03:00
|
|
|
make # builds & strips ./bantam (c++ -std=c++20 -O2 -march=native -s -Wall -Wextra -Wpedantic)
|
2026-10-14 00:01:03 +03:00
|
|
|
make clean # remove build artifacts
|
|
|
|
|
make install # install to $(DESTDIR)/usr/local/bin/bantam
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The default `make` produces a single binary, `bantam`, with no runtime
|
|
|
|
|
dependencies beyond libc, libcurl and libreadline.
|
|
|
|
|
|
|
|
|
|
## Running
|
|
|
|
|
|
|
|
|
|
All implementations read `model.cfg` (or `.bantam.cfg`, which takes priority
|
|
|
|
|
if present) from the current working directory.
|
|
|
|
|
|
|
|
|
|
1. Configure `model.cfg` (or `.bantam.cfg`, which takes priority) with your
|
|
|
|
|
API settings:
|
|
|
|
|
|
|
|
|
|
```ini
|
|
|
|
|
endpoint=https://api.kilo.ai/api/openrouter
|
|
|
|
|
model=openrouter/free
|
|
|
|
|
temperature=0.7
|
|
|
|
|
api_key=your_api_key_here
|
|
|
|
|
stream=true
|
|
|
|
|
context_window=200000
|
|
|
|
|
max_tool_res=65536
|
|
|
|
|
reasoning_effort=high
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. Interactive mode:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
./bantam
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In interactive mode, prompts can span multiple lines: press **Ctrl+J** to
|
|
|
|
|
insert a real line break (the cursor moves to the next line), then **Enter**
|
|
|
|
|
to submit the whole multi-line prompt. Bracketed paste is enabled
|
|
|
|
|
(`ESC[?2004h`) while editing, so a multi-line block pasted from the
|
|
|
|
|
clipboard is inserted as literal line breaks and only the final **Enter**
|
|
|
|
|
submits it. The C++ port ships its own raw-mode line editor, working
|
|
|
|
|
everywhere with no third-party dependencies. It supports arrow keys and
|
|
|
|
|
Up/Down for history, Backspace / Delete / Ctrl+D (on an empty line) to
|
|
|
|
|
delete, and Emacs-style editing combos: **Ctrl+A** (start of line),
|
|
|
|
|
**Ctrl+E** (end of line), **Ctrl+B** / **Ctrl+F** (move by character),
|
|
|
|
|
**Ctrl+W** (delete previous word), **Ctrl+K** (kill to end of line),
|
|
|
|
|
**Ctrl+U** (kill to start of line), **Ctrl+Left** / **Ctrl+Right** (move by
|
|
|
|
|
word), and **Home** / **End** keys. **Ctrl+C** clears the line /
|
|
|
|
|
interrupts an in-flight run, and **Ctrl+D** on an empty line exits.
|
|
|
|
|
|
|
|
|
|
After every interaction, Bantam displays token usage (prompt tokens,
|
|
|
|
|
cached / uncached breakdown when supported by the provider, completion
|
|
|
|
|
tokens, and context-window utilization):
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
[openrouter/free: 1420 prompt (1000 cached, 420 uncached) + 85 completion | context: 1420/262144 (0.5%)]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Sessions are saved under `~/.bantam/sessions/` and can be managed with
|
|
|
|
|
these commands:
|
|
|
|
|
|
|
|
|
|
- `/save [name]` — save the entire conversation to a session file (named
|
|
|
|
|
`name`, or defaulting to the MD5 hash of the current project directory)
|
|
|
|
|
and generate its summary.
|
|
|
|
|
- `/continue` (alias `/cont`) — continue/autoload the session corresponding
|
|
|
|
|
to the current project directory.
|
|
|
|
|
- `/list` — list saved sessions (newest first) with their ids, timestamps,
|
|
|
|
|
message counts and summaries (marking the current project's session).
|
|
|
|
|
- `/load <id>` — load a saved session (exact id or unique prefix) and
|
|
|
|
|
continue from there.
|
|
|
|
|
- `/compact` — compact context down to the system message and a concise
|
|
|
|
|
summary using the LLM; the compaction prompt is appended to the
|
|
|
|
|
conversation to derive the summary, then the conversation is reset to
|
|
|
|
|
`[system, summary-user-message]`.
|
|
|
|
|
- `/cfg <param> [val]` — inspect or update a configuration parameter live
|
|
|
|
|
(writes to `.bantam.cfg`).
|
|
|
|
|
- `/model [val]` — alias for `/cfg model` (inspect or set the model).
|
|
|
|
|
- `/endpoint [val]` — alias for `/cfg endpoint` (inspect or set the API
|
|
|
|
|
endpoint).
|
|
|
|
|
- `/skill` — with no argument, list every skill under the configured
|
|
|
|
|
skills directory (or report that none are configured); with
|
|
|
|
|
`<name> [prompt]`, load `<skills_dir>/<name>/SKILL.md` (or an absolute
|
|
|
|
|
path when no skills dir is set) and send its contents prefixed to the
|
|
|
|
|
optional `prompt` as the next user turn.
|
|
|
|
|
- `/models` — query the `/models` path on the current inference endpoint
|
|
|
|
|
and print a plain list of supported model IDs, marking the currently
|
|
|
|
|
configured model with a leading `* `.
|
|
|
|
|
- `!<cmd>` — execute a shell command directly through `bash` without
|
|
|
|
|
adding the result to the conversation context.
|
|
|
|
|
- `/help` — show all supported commands.
|
|
|
|
|
- `/clear` — reset the conversation to just the system prompt.
|
|
|
|
|
- `/quit` — exit.
|
|
|
|
|
|
|
|
|
|
When context-window usage reaches **60% or higher**, Bantam automatically
|
|
|
|
|
offers to compact the conversation:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
Context usage is at 62.4% (163840 / 262144 tokens). Compact conversation? [Y/n]:
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Pressing **Ctrl+C** during an active inference run or long-running shell
|
|
|
|
|
execution cleanly interrupts the turn without appending partial or
|
|
|
|
|
malformed responses to the conversation context.
|
|
|
|
|
|
|
|
|
|
The current conversation is also **auto-saved** to
|
|
|
|
|
`~/.bantam/sessions/<project-md5>.json` after every turn, on `/clear`,
|
|
|
|
|
`/load`, `/compact`, `/continue`, and on exit — so you can always run
|
|
|
|
|
`/continue` (or `/cont`) to resume where you left off.
|
|
|
|
|
|
|
|
|
|
3. File input mode:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
./bantam prompt.txt
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If the file's first line (or the argument) starts with `!`, the rest is run
|
|
|
|
|
as a direct shell command through `bash` and the program exits (the output
|
|
|
|
|
is not added to the conversation).
|
|
|
|
|
|
|
|
|
|
## Model configuration parameters
|
|
|
|
|
|
|
|
|
|
(shared with the Go and C implementations; `.bantam.cfg` takes priority over
|
|
|
|
|
`model.cfg` when both exist — both are plain `key=value` with `#` comments.
|
|
|
|
|
Values defined in `.bantam.cfg` override `BANTAM_*` environment variables;
|
|
|
|
|
when `.bantam.cfg` is absent, `BANTAM_*` environment variables override
|
|
|
|
|
`model.cfg` and built-in defaults.)
|
|
|
|
|
|
|
|
|
|
- `endpoint` (base OpenAI-compatible API URL, default
|
|
|
|
|
`https://api.kilo.ai/api/openrouter`; falls back to `BANTAM_ENDPOINT`).
|
|
|
|
|
- `model` (model name, default `openrouter/free`; falls back to
|
|
|
|
|
`BANTAM_MODEL`).
|
|
|
|
|
- `temperature` (model temperature, default `0.7`; falls back to
|
|
|
|
|
`BANTAM_TEMP` or `BANTAM_TEMPERATURE`).
|
|
|
|
|
- `api_key` (API key / Bearer token, optional; falls back to
|
|
|
|
|
`BANTAM_API_KEY`; set to `-` or left blank in the config file to explicitly
|
|
|
|
|
defer to `BANTAM_API_KEY`).
|
|
|
|
|
- `stream` (stream response tokens in real-time, default `true`; falls back to
|
|
|
|
|
`BANTAM_STREAM`).
|
|
|
|
|
- `color` (ANSI coloring: `auto` (TTY-detected, default), `always`, or
|
|
|
|
|
`never`; disabled by `NO_COLOR` / `BANTAM_NO_COLOR` env vars, falls back to
|
|
|
|
|
`BANTAM_COLOR`).
|
|
|
|
|
- `timeout` (HTTP timeout in seconds for LLM API calls, default `300`; bounds
|
|
|
|
|
connection setup and time-to-first-byte so long streaming responses are not
|
|
|
|
|
cut off mid-stream; falls back to `BANTAM_TIMEOUT`).
|
|
|
|
|
- `shell_timeout` (timeout in seconds for `bash` shell commands, default
|
|
|
|
|
`120`; falls back to `BANTAM_SHELL_TIMEOUT`).
|
|
|
|
|
- `max_al_iterations` (max tool-call loop iterations per `AL()` invocation,
|
|
|
|
|
default `1000`; falls back to `BANTAM_MAX_AL_ITERATIONS`).
|
|
|
|
|
- `context_window` (context window size in tokens, auto-discovered from
|
|
|
|
|
`/models` API if available, fallback to this setting, default `262144`;
|
|
|
|
|
falls back to `BANTAM_CONTEXT_WINDOW`).
|
|
|
|
|
- `max_tool_res` (maximum number of bytes of a tool result that may be sent
|
|
|
|
|
into the model context directly, default `65536`; larger results are written
|
|
|
|
|
to a unique file under `$TMPDIR/bantam/toolres` and replaced by a short
|
|
|
|
|
instruction naming the file and its line count so it can be read in parts
|
|
|
|
|
using the `read` tool, and the file is deleted once the round ends; falls
|
|
|
|
|
back to `BANTAM_MAX_TOOL_RES`).
|
|
|
|
|
- `reasoning_effort` (reasoning effort level, forwarded to chat completions
|
|
|
|
|
API, default `high`; falls back to `BANTAM_REASONING_EFFORT`).
|
|
|
|
|
|
|
|
|
|
- `bantam_tools_dir` (optional path to a directory of extra shell tools; when
|
|
|
|
|
set, Bantam appends `"Extra shell tools can be found at <dir>"` to the
|
|
|
|
|
system prompt at startup. Falls back to `BANTAM_TOOLS_DIR`. Agent-internal
|
|
|
|
|
hint, not forwarded to the API.)
|
|
|
|
|
- `bantam_skills_dir` (optional path to a directory of reusable *skills*, each
|
|
|
|
|
in its own subdirectory as `<skill_name>/SKILL.md`. When set, Bantam appends
|
|
|
|
|
`"Skills may be discovered and invoked from <dir>"` to the system prompt and
|
|
|
|
|
the `/skill <skill_name> [prompt]` command loads a skill's `SKILL.md` and
|
|
|
|
|
runs it as a prompt. Falls back to `BANTAM_SKILLS_DIR`. Agent-internal
|
|
|
|
|
hint, not forwarded to the API.)
|
|
|
|
|
|
|
|
|
|
The C++ port supports SOCKS5 proxying via the `SOCKS_PROXY` (or
|
|
|
|
|
`socks_proxy`) environment variable (e.g. `SOCKS_PROXY=socks5://127.0.0.1:1080`
|
|
|
|
|
or `SOCKS_PROXY=127.0.0.1:1080`), falling back to standard `HTTP_PROXY` /
|
|
|
|
|
`HTTPS_PROXY` environment variables.
|
|
|
|
|
|
|
|
|
|
When enabled, the interactive console uses a subtle ANSI palette: the
|
|
|
|
|
pending-request status `...requesting...` is dimmed bold, reasoning markers
|
|
|
|
|
are cyan, reasoning text is dim, `[tool call: ...]` traces are yellow,
|
|
|
|
|
`[tool result: ...]` headers are green, tool result bodies are dim (red for
|
|
|
|
|
tool errors / unknown tools), and errors / network retries are red. Tool
|
|
|
|
|
result payloads fed back to the LLM are never colored.
|
|
|
|
|
|
|
|
|
|
## The agentic loop
|
|
|
|
|
|
|
|
|
|
1. **Initialization**: read the config file (`.bantam.cfg` if present, else
|
|
|
|
|
`model.cfg`). Discover the context-window size from the `/models` endpoint
|
|
|
|
|
(or fall back to `context_window`, default `262144` tokens). Prepare the
|
|
|
|
|
messages array starting with the built-in system prompt.
|
|
|
|
|
2. **Input processing**: take the user prompt (command-line file parameter or
|
|
|
|
|
interactive stdin). If prefixed with `!`, execute the command directly via
|
|
|
|
|
`bash` without appending to the conversation context. Otherwise append
|
|
|
|
|
`{"role": "user", "content": prompt}` and invoke `AL(cfg, messages)`.
|
|
|
|
|
3. **Agentic loop (`AL`)**:
|
|
|
|
|
- Send `messages` and tool definitions (`bash`, `read`, `write`) to the
|
|
|
|
|
OpenAI-compatible `/chat/completions` API with custom request headers (see
|
|
|
|
|
below) and `stream_options: {"include_usage": true}`.
|
|
|
|
|
- Support context cancellation (on `SIGINT` / Ctrl+C) to cleanly abort
|
|
|
|
|
in-flight requests without appending incomplete messages.
|
|
|
|
|
- On network or HTTP failure, retry using Fibonacci backoff delays
|
|
|
|
|
(`1s, 1s, 2s, 3s, 5s, 8s, 13s, 21s, 34s`). A `4xx` error other than the
|
|
|
|
|
recoverable invalid-assistant-message case fast-fails.
|
|
|
|
|
- If `stream=true`, parse SSE data chunks (`data: {...}`) in real time to
|
|
|
|
|
stream reasoning content (`reasoning_content`) and response text directly
|
|
|
|
|
to stdout, bracketing the reasoning block with
|
|
|
|
|
`--- reasoning start ---` / `--- reasoning end ---` markers, rendering
|
|
|
|
|
Markdown and tables constrained to terminal width.
|
|
|
|
|
- Reconstruct the assistant message and track usage tokens
|
|
|
|
|
(`prompt_tokens`, `completion_tokens`, cached tokens). If `tool_calls`
|
|
|
|
|
exist, trace the call (`[tool call: name(args)]`), validate JSON
|
|
|
|
|
arguments, execute the requested tool (`bash`, `read`, or `write`; also
|
|
|
|
|
accepting legacy `shell_exec` and `write_file`), trace the result
|
|
|
|
|
(`[tool result: name]`), append the tool response
|
|
|
|
|
`{"role": "tool", "tool_call_id": id, "content": result}`, and repeat the
|
|
|
|
|
loop.
|
|
|
|
|
- If no tool calls remain or `max_al_iterations` is reached, return the
|
|
|
|
|
updated messages list and turn usage stats.
|
|
|
|
|
4. **Post-turn reporting & compaction**:
|
|
|
|
|
- Display token usage and context-window percentage.
|
|
|
|
|
- If context usage is `>= 60%`, prompt the user to compact.
|
|
|
|
|
- Compaction appends a compaction prompt as a user message to derive the
|
|
|
|
|
summary, invokes the LLM, and then resets the conversation to the system
|
|
|
|
|
prompt plus a `user` message carrying the resulting summary.
|
|
|
|
|
|
|
|
|
|
If the API rejects the request with an `Invalid assistant message: content or
|
|
|
|
|
tool_calls must be set` error (usually caused by a previously cut-off stream
|
|
|
|
|
that left an empty assistant message in the session), Bantam strips the last
|
|
|
|
|
`assistant`-role message from the session and retries the call.
|
|
|
|
|
|
|
|
|
|
### Custom request headers
|
|
|
|
|
|
|
|
|
|
All endpoints receive custom request headers mimicking OpenCode:
|
|
|
|
|
`User-Agent: opencode/1.18.31 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.14`,
|
|
|
|
|
`x-opencode-client: cli`, `x-opencode-project: global`,
|
|
|
|
|
`x-opencode-session: <ses_...>`, and a fresh `x-opencode-request: <msg_...>`
|
|
|
|
|
per call (the 12-hex timestamp prefix in `x-opencode-request` is the bitwise
|
|
|
|
|
inverse of `x-opencode-session`). The `Authorization: Bearer <api_key>` header
|
|
|
|
|
is added whenever `api_key` is set and not `-`.
|
|
|
|
|
|
|
|
|
|
### Prompt-injection defense
|
|
|
|
|
|
|
|
|
|
Tool arguments and tool outputs are sanitized by filtering out non-printable
|
|
|
|
|
and space-like Unicode characters (keeping ASCII space, tab, newline, and
|
|
|
|
|
printable Unicode), protecting against indirect prompt injection before
|
|
|
|
|
anything is sent back to the model.
|
|
|
|
|
|
|
|
|
|
## Tool call definitions
|
|
|
|
|
|
|
|
|
|
### `read` tool
|
|
|
|
|
|
|
|
|
|
- Parameters: `filePath` (string, required; also accepts `path`); `offset`
|
|
|
|
|
(integer, optional, 1-indexed, default 1); `limit` (integer, optional,
|
|
|
|
|
default 2000).
|
|
|
|
|
- Action: if the target is a regular file, returns numbered lines in
|
|
|
|
|
`<line>: <content>` format; if a directory, returns a list of directory
|
|
|
|
|
entries (subdirectories include a trailing `/`).
|
|
|
|
|
|
|
|
|
|
### `write` tool
|
|
|
|
|
|
|
|
|
|
- Parameters: `filePath` (string, required; also accepts `path`); `offset`
|
|
|
|
|
(integer, optional, byte offset); `del_bytes` (integer, optional); `content`
|
|
|
|
|
(string, required, may be empty).
|
|
|
|
|
- Action: if `offset` and `del_bytes` are both omitted, the entire file is
|
|
|
|
|
overwritten with `content` (the file and any necessary parent directories
|
|
|
|
|
are created if missing); otherwise `content` is written at `offset`,
|
|
|
|
|
optionally deleting `del_bytes` bytes first (splicing prefix + content +
|
|
|
|
|
suffix and never appending to the end of an existing file). (Also accepted as
|
|
|
|
|
legacy `write_file`.)
|
|
|
|
|
|
|
|
|
|
### `bash` tool
|
|
|
|
|
|
|
|
|
|
- Parameters: `command` (string, required); `workdir` (string, optional).
|
|
|
|
|
- Action: run `command` via `bash -c` subject to `shell_timeout`
|
|
|
|
|
(default `120s`) and return `output + '\nexit: ' + exit_code`. (Also
|
|
|
|
|
accepted as legacy `shell_exec`.)
|
|
|
|
|
|
|
|
|
|
## Extra tools and skills
|
|
|
|
|
|
|
|
|
|
Because Bantam's built-in tools include `bash`, helper scripts can be invoked
|
|
|
|
|
directly by the agent through `bash`. Point Bantam at a directory of helpers
|
|
|
|
|
with the `bantam_tools_dir` key (or `BANTAM_TOOLS_DIR`); when set, the line
|
|
|
|
|
`Extra shell tools can be found at <dir>` is appended to the system prompt. A
|
|
|
|
|
*skill* is a reusable instruction bundle: a directory containing a `SKILL.md`
|
|
|
|
|
file, pointed to by `bantam_skills_dir` (or `BANTAM_SKILLS_DIR`), and run with
|
|
|
|
|
`/skill <name> [prompt]`.
|
|
|
|
|
|
|
|
|
|
## Memory safety
|
|
|
|
|
|
|
|
|
|
The C++ port leans on the language's standard library and RAII to minimize
|
|
|
|
|
memory-management hazards: all dynamic text uses `std::string`, message
|
|
|
|
|
collections use `std::vector`, and curl header lists and streaming state are
|
|
|
|
|
wrapped in RAII types (`CurlHeaders`, `StreamCtx`) that free themselves on
|
|
|
|
|
scope exit. There is no hand-rolled allocator and no manual `free` of message
|
|
|
|
|
or tool-call data, so use-after-free and double-free are structurally
|
2026-10-14 08:36:39 +03:00
|
|
|
unlikely. A lightweight, native RFC 8259 JSON engine (`struct Json` in
|
|
|
|
|
`json.cpp`) handles all JSON parsing and serialization using standard C++
|
|
|
|
|
containers instead of an unsafe C API or a heavy header-only template library.
|
2026-10-14 00:01:03 +03:00
|
|
|
|
|
|
|
|
## Credits
|
|
|
|
|
|
|
|
|
|
Created by Luxferre in 2026, released into the public domain with no
|
|
|
|
|
warranties.
|