Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@zhuerle/terminus-2-cli) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
terminus-2-cli
Standalone Node.js port of Harbor's Terminus2 agent.
The Python terminus-2 agent assumes a host-side loop that talks to a
container-side tmux through docker exec. This package collapses that into a
single in-container Node.js binary so the agent loop, tmux interaction, and
LLM calls all happen on the same side of the docker boundary — matching the
terminus-codeinf deployment variant, but
with no Python wheel to bootstrap.
It is intentionally small (zero npm runtime deps) and faithful to the
Terminus2 behavior that matters for benchmarks: prompt template, XML/JSON
parsers, tmux send + capture loop, task_complete two-step confirmation,
and per-step trajectory dumps.
What's ported
- Prompt templates (
prompts/terminus-{xml,json}-plain.txt, copied verbatim from the Python repo) - Both parsers (XML plain + JSON plain), with the same warnings and auto-fixes
- tmux session driver (
script(1)-allocated PTY →tmux new-session -d), send-key chunking under the ~16 KB tmux command-buffer limit - Main agent loop with batched send + capture, observation feedback,
task_completeconfirmation, parser-error re-prompt - Per-step trajectory in an ATIF-shaped subset, written to
<logs-dir>/trajectory.json
What's not ported (yet)
- Context-length summarization / truncation (the Python summarization subagent flow is ~1k LOC — add only if you hit it)
- Tokenizer-based token counting (we trust the API's
usageblock) - Asciinema recording, skill discovery, subagent metrics, linear-history splitting, output-length salvage
Requirements
- Node.js >= 18.17 (uses built-in
fetchandnode:util.parseArgs) tmuxandscriptavailable on PATH inside the container- An OpenAI-compatible chat-completions endpoint (works with vLLM, LiteLLM-proxy, SGLang, OpenAI, Anthropic via LiteLLM)
Standalone usage
cat > /tmp/cfg.json <<EOF
{
"model_name": "openai/gpt-4o",
"api_base": "https://api.openai.com/v1",
"api_key": "$OPENAI_API_KEY",
"parser_name": "xml",
"temperature": 0.2,
"max_turns": 30
}
EOF
echo "Print 'hello world' to the terminal and stop." > /tmp/instruction.txt
mkdir -p /tmp/agent-logs
./bin/terminus-2-cli.mjs run \
--config /tmp/cfg.json \
--instruction /tmp/instruction.txt \
--logs-dir /tmp/agent-logs \
--session-id demoAfter the run:
/tmp/agent-logs/trajectory.json— per-step trajectory/tmp/agent-logs/context.json— final token / cost counters/tmp/agent-logs/exception.txt— only present on failure
Config schema
The --config JSON accepts both Python-style snake_case and JS-style
camelCase keys; CLI flags override config values.
| Key | Type | Notes |
|---|---|---|
model_name |
string | required (or pass --model) |
api_base |
string | OpenAI-compatible base URL |
api_key |
string | falls back to OPENAI_API_KEY env |
parser_name |
"xml" | "json" |
default "xml" |
max_turns |
number | default 1,000,000 (i.e. unbounded) |
temperature |
number | default 0.7 |
top_p |
number | optional |
max_new_tokens |
number | optional |
reasoning_effort |
string | OpenAI-style |
max_thinking_tokens |
number | Anthropic-style; sent as thinking.budget_tokens |
llm_request_timeout_sec |
number | default 600 |
llm_extra_body |
object | merged into the request body |
llm_headers |
object | extra HTTP headers |
tmux_pane_width / tmux_pane_height |
number | default 160×40 |
Running under harbor
src/harbor/agents/installed/terminus_2_cli.py registers this CLI as
harbor's terminus-2-cli agent. The host wrapper tars up this directory,
uploads it into the task container, runs install-terminus-2-cli.sh.j2 to
install Node and extract the source, then invokes:
/usr/local/bin/terminus-2-cli run \
--config /logs/agent/terminus-2-cli-config.json \
--instruction /logs/agent/terminus-2-cli-instruction.txt \
--logs-dir /logs/agent \
--session-id <trial-session-id>harbor-level kwargs (--agent-kwarg max_turns=30, etc.) are forwarded into
the config JSON exactly the same way TerminusCli does it.
Tests
node --test test/Parser + utility tests run without external services. The loop test
(test/loop.test.mjs) needs tmux on PATH; it stubs the LLM and verifies a
real tmux command is dispatched and observed.