ti-agent
v0.1.14
Published
Effect v4 native AI coding agent CLI
Maintainers
Readme
ti-agent
Minimal ti CLI and interactive composer.
Install
ti-agent is the Node-runtime install path for the ti binary and requires
Node.js 20 or newer. The 0.1.12 npm package set requires one-time
ti-code-evals publication bootstrap; until it is available, use the GitHub
Release binaries when installing 0.1.12.
After npm publication is available:
npm install -g ti-agent
ti --version
ti auth
ti auth set-key <exa|opencode-zen>
ti auth remove <exa|opencode-zen>Run from npm without installing globally after publication:
pnpm dlx ti-agent auth
npx ti-agent auth
bunx ti-agent authPin an npm install-script version after publication with TI_VERSION:
curl -fsSL https://raw.githubusercontent.com/agustif/ti/main/install.sh | TI_VERSION=0.1.12 shCommands
ti
ti login chatgpt
ti logout chatgpt
ti auth
ti models [chatgpt|obvious]
ti chat [--provider <openai|chatgpt|obvious>] [--session <id>] [--model <model>] <prompt>
ti resume --last
ti tool <read|write|edit|apply_patch|bash|py|code|eval> '<json-args>'
ti update [--check|--dry-run] [--version <version>] [--json]
ti --versionti update delegates npm/pnpm installs to the owning global package manager.
Standalone release binaries are updated from GitHub Releases after verifying
SHA256SUMS.txt; Windows standalone self-replacement is intentionally refused
until a next-run replacement flow exists. The supervised source-patch /
daemon-handoff path from RFC-0007 remains draft-only; shipped updates are
next-launch activation, not a live worker swap.
Runtime bundles
The portable runtime probe builds through Rslib:
pnpm --filter ti-agent runtime:buildThat single build emits:
dist/runtime/node/runtime-probe.js
dist/runtime/llrt/runtime-probe.js
dist/runtime/quickjs-ng/runtime-probe.jsDurable logs
ti keeps the terminal quiet by default. Enable durable Effect JSON logs only when
debugging stream/provider behavior:
TI_LOG=1 ti
TI_LOG_DIR=/tmp/ti-logs ti
TI_LOG_PATH=/tmp/ti.jsonl ti chat --provider chatgpt "hello"TI_LOG=1writes.ti/logs/ti-<timestamp>-<pid>.jsonl.TI_LOG_DIRchooses a log directory;TI_LOG_PATHchooses the exact JSONL file.TI_LOG_LEVELdefaults toDebugwhen logging is enabled.TI_LOG_STREAM_TEXT=1adds short content/reasoning previews. Without it, logs stay metadata-only.- Stream logs use the current OpenTelemetry GenAI semantic attribute names such as
gen_ai.operation.name,gen_ai.provider.name,gen_ai.request.model,gen_ai.response.finish_reasons, and token usage when the provider returns it. These GenAI conventions are still marked Development by OpenTelemetry. - Provider diagnostics are hidden from the UI but logged when durable logging is enabled, including raw SSE event types so reasoning-summary wiring can be verified live.
Local trace stack
For long Obvious tool-chain failures, run the local OTLP/Jaeger debug stack:
docker compose -f compose.debug.yaml up -d jaeger otel-collector
TI_OTEL=1 OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces \
TI_LOG_PATH=/tmp/ti-debug.jsonl TI_LOG_STREAM_TEXT=1 tiOpen Jaeger at http://localhost:16686 and select service ti-agent.
For an isolated containerized ti session against the host Obvious API:
export OBVIOUS_CHAT_COMPLETIONS_API_KEY=...
TI_DEBUG_CWD="$PWD" docker compose -f compose.debug.yaml --profile cli run --rm ti-debugThe container writes sessions and durable logs under .ti/debug-container/.
Interactive commands
Inside ti:
/help— show commands and shortcuts/version— show theti-agentpackage version, binary, runtime, and entrypoint/status— show version, repo, model, auth, session, and shortcuts/tools— list built-in tools/read <path>— preview a file and persist the full output to the session/bash <command>— run a shell command/py <code>— run Python throughuv,python3, orpython/tool <name> <json>— run any built-in tool with JSON args/agent show <id>— inspect a child run and its recent activity tail/agent steer <id> <text>— steer a running child run/agent cancel <id>— cancel a child run; repeated cancels are idempotent/session— show the current session id/quitorctrl-c— exit
Child-agent cards keep only the recent tail of activity. Once a child reaches a terminal state, the UI stops showing stale running controls and stale result state.
The native CLI/TUI also registers eval, a durable local evaluation tool. To
prepare and run the official SWE-bench gold smoke instance while retaining its
virtual environment, Docker logs, and summary files under .ti/evals/swe-bench:
ti tool eval '{"operation":"prepare"}'
ti tool eval '{"operation":"gold_smoke","timeoutSeconds":1800}'Gold smoke reuses retained official Docker images by default. Pass
"forceRebuild":true only when explicitly reconstructing those images.
dockerHost overrides auto-detected Docker socket selection when needed;
reinstallHarness recreates the retained SWE-bench environment separately from
the official harness forceRebuild Docker-image option.
Interactive shortcuts:
Enter— submit prompt or commandUp/Down— browse prompt historyCtrl-L— clear screenCtrl-T/Ctrl-O— show latest tool detailsCtrl-D— toggle debug overlayEsc— request interrupt for the active runCtrl-C— exit
Code Mode
Code Mode is an optional harness over the existing tool registry. It gives the
model one code tool whose JavaScript function can call current tools through
codemode.*:
ti tool code '{"code":"async () => codemode.read({ path: \"package.json\" })"}'
ti tool code '{"code":"async () => { const pkg = await codemode.readJson({ path: \"package.json\" }); return pkg.name; }"}'
TI_TOOL_MODE=code tiThe output is always parseable pretty JSON produced through Effect's formatter surface. Large values are truncated into a valid JSON envelope instead of returning a broken partial JSON string.
Tool calls preserve the raw tool result in the trace. When a tool returns JSON
text, parse it explicitly with codemode.readJson(args),
codemode.json.read(args), codemode.json.tool(name, args), or
codemode.json.parse(text). Automatic double-parsing is avoided so plain text
tool output and audit traces stay faithful to what the tool returned.
The current executor runs in the current JavaScript runtime. It is useful for local orchestration and runtime-host experiments, but it is not a sandbox or security boundary.
Runtime Policy
- Optional diagram or media renderers are not part of the default CLI. If they return, they should live in a small plugin/skill area rather than in core.
- The interactive agent has no default max model-round or tool-call cap.
Configure
TI_MAX_MODEL_ROUNDSorTI_MAX_TOOL_CALLSonly for a specific orchestrator/subagent policy. Values must be base-10 whole numbers; leave them unset for unbounded runs. TI_REPEATED_TOOL_BATCH_LIMITcontrols the repeated-batch doom-loop guard. Leave it unset for the runtime default, set it to0to disable it, or use a base-10 whole number to override the limit.
OpenAI WebSocket Transport
OpenAI can also use the experimental Responses WebSocket transport:
TI_OPENAI_TRANSPORT=responses-websocket tiThe default remains HTTP SSE. WebSocket mode requires a runtime whose
globalThis.WebSocket supports handshake headers; Node 25+ works in local
testing, while QuickJS/LLRT support depends on the selected host.
Local Obvious Provider
obvious calls the local OpenAI-compatible Obvious /responses SSE endpoint
directly and defaults to the Obvious default model. This matches the Responses wire protocol
used by Codex and preserves structured function/tool calls:
export OBVIOUS_CHAT_COMPLETIONS_API_KEY="obv_prj_..."
export OBVIOUS_API_BASE_URL="http://localhost:4041/api/v1"
ti models obvious
ti chat --provider obvious "Reply with exactly: TI_OBVIOUS_OK"
TI_PROVIDER=obvious tiDirect-mode aliases are also accepted for compatibility with external launchers:
CODEX_DIRECT_API_KEY / CODEX_DIRECT_BASE_URL,
OBDEX_DIRECT_API_KEY / OBDEX_DIRECT_BASE_URL,
and OPENAI_API_KEY / OPENAI_BASE_URL.
Within the TUI, /provider obvious switches subsequent turns to Obvious,
/models fetches the active provider catalog, and /model <id> switches the
active model. TI_PROVIDER=obvious selects Obvious at startup. Set
OBVIOUS_MODEL or pass --model to override the default. The Codex Responses
proxy is not needed for ti.
Notes
chatuses the configured provider layer and stores turns in the active session when session persistence is enabled.login/logout/authremain wired for ChatGPT OAuth;models obviousreads the local Obvious model catalog.- ChatGPT OAuth metadata is stored through the auth store reported by
ti auth. ti auth set-key exaandti auth set-key opencode-zenread keys without echoing them. API-key values prefer macOS Keychain or Linux Secret Service, falling back to the permissions-restricted auth file only when unavailable./authis status-only and never accepts inline secret text.- Live
openaichat requiresOPENAI_API_KEY; liveobviouschat requiresOBVIOUS_CHAT_COMPLETIONS_API_KEY. - The default
ti-core-toolsplugin contributesread,write,edit,apply_patch,bash,py,code, andpreload_cli_tool. TI_TUI_SESSION_DIRcan override the interactive session storage directory.TI_TUI_SESSION_IDremains an internalresumehandoff variable while the current interactive boot path still snapshots env at startup.
