Skip to content

Releases: igormcsouza/tether

v0.2.3 Small-Model Robustness

Choose a tag to compare

@igormcsouza igormcsouza released this 20 Oct 22:09
ec32d63

Dogfooding fixes: the issues came from running Tether with a small model (GLM-5.3) on its own backlog.

Features

  • tether read <id> --full (#72): the CLI now accepts the same --full form as the in-session agent read; it prints the full result (already the CLI default), --digest still gives the compact card.

Fixes

  • Gate errors vs failures (#33): a broken verify gate (sandbox violation, exit 124/126/127) fails the session immediately with Verification gate ... misconfigured: <reason> instead of burning the 3-failure abort budget; tether stats shows a GATE_ERR column.
  • edit write overwrite summary (#40): overwriting an existing file reports Replaced N lines with M (X removed, Y added; first removed: ...) and points to edit replace --lines a:b when the file shrank.
  • Skill tools.py warning (#24): a @tool defined in tools.py but not listed in the skill's tools: now warns at load (0 prompt tokens); docs say the tools stay opt-in.
  • Cycle detection (#39): repeated multi-command cycles (e.g. cat / sed / pytest, or alternating sed -n ranges) trigger a deterministic [CYCLE DETECTED] nudge and a new cycle_stall event type, shown as CYCLES in tether stats.
  • Provider retry (#70): HTTP providers retry timeouts, network errors and 429/5xx twice with backoff, honour timeout from providers.yaml for all kinds, and fail with a ProviderError naming provider, model and timeout instead of a bare ReadTimeout.
  • No more re-read loops (#69): the latest read of each of the last 4 files stays unfolded until that path is edited (or re-read); the fold hint only mentions mem recall when mem is enabled. Static prompt prefix unchanged.
  • Clearer errors (#71): a provider 401/403 names the provider and the api_key_env as missing or rejected (never its value); a declared but empty api_key_env fails before the first request; a disabled built-in tool says it is disabled and how to enable it.

Docs: https://igormcsouza.github.io/tether/release-notes/

v0.2.2 Provider Dialects, Schema Output & Context Config

Choose a tag to compare

@igormcsouza igormcsouza released this 19 Oct 15:12
125b386

Dogfooding fixes: Tether implemented most of this release itself through its own CLI and a claude -p provider.

Features

  • {schema} placeholder (#51) for command providers: constrain output to the act schema (e.g. claude -p --json-schema '{schema}'); replies may be structured objects with cmd/stdin. Measured: with claude -p this adds ~2k prompt tokens per call, so it is a reliability option, not a saving.
  • tether misses (#53): list unparsed model replies (nudges) as fixture-ready JSONL for tests/fixtures/dialects.jsonl.

Fixes

  • Configurable context budget and fold window (#54): --context-tokens / --fold-after on tether run and tether pipeline, context_tokens / fold_after on MCP tether_run, and per-provider keys in providers.yaml. The 8k context and fold-after-2 defaults made large-context backends re-read the same files forever.
  • Table-driven tool-call dialect extractors (#52): built-in <tool_call> JSON, raw JSON, <parameter name="cmd"> blocks and text act(...), extendable with tether.register_dialect or a dialects: regex list in providers.yaml.

Docs: https://igormcsouza.github.io/tether/reference/providers/

v0.2.1 Declarative Providers

Choose a tag to compare

@igormcsouza igormcsouza released this 19 Oct 14:19
ee85618

Add model backends without writing code.

Features

  • Declarative providers (#49): ~/.tether/providers.yaml (override with TETHER_PROVIDERS, never read from the workspace) maps a model-id prefix to a provider. Kinds: openai (OpenRouter, vLLM, Groq, LM Studio...), ollama, anthropic and command, which wraps any CLI that prints JSON (for example claude -p --tools "") with {model}, {system} and {conversation} placeholders, JSON-path reply and token usage, and a timeout. argv is executed directly, never through a shell. Works in tether run, tether pipeline, the SDK and tether mcp.
  • Built-in prefixes (ollama, openai, anthropic, claude) cannot be shadowed.

Docs: https://igormcsouza.github.io/tether/reference/providers/#declarative-providers

v0.2.0 MCP Server & Agent-to-Agent Interface

Choose a tag to compare

@igormcsouza igormcsouza released this 19 Oct 13:16
8e67686

Tether as a subagent for the harness you already use (Claude Code, Codex, Cursor, Gemini CLI, Copilot): MCP server, JSON output and exit codes (#46). See Use Tether Inside Your Harness.

Features

  • MCP server (optional extra, pip install "tether-sdk[mcp]"; without it tether mcp warns and exits 1): tether mcp over stdio with tether_run|status|wait|read|send|list|stats|query.
  • --json on run, pipeline, status, list, read, wait, send, stats; stable schema v: 1.
  • Exit codes: 0 completed, 1 usage, 2 waiting for input, 3 gate failed, 4 max steps, 5 worker error. Failure text now goes to stderr.
  • Harness(output_schema=...) / --output-schema, --result-file (JSON Schema subset enforced as a done gate), tether events <id> [--follow].

Fixes

  • Worker errors keep the exception type and store the traceback as a tool_error turn (#41).
  • ollama no longer silently substitutes an installed model on 404; it fails with the installed list. Opt back in with TETHER_OLLAMA_FALLBACK=1 (#21).

Behavior changes

  • tether wait now exits non-zero when a session failed or needs input (it always returned 0 before).

v0.1.4 Security hardening

Choose a tag to compare

@igormcsouza igormcsouza released this 18 Oct 23:17
abe7c33

Security hardening from a red-team run of ollama/qwen3.5:9b against v0.1.3 (hidden prompt injection in a README exfiltrated a file; docker.sock was reachable inside bwrap).

Security

  • Sandbox: unix sockets under /run (including docker.sock, a host escape for docker-group users) are masked; /home, /media, /mnt, /srv and /var/tmp are hidden behind tmpfs. Previously python could read them and connect to the socket despite the command-string guard.
  • Sandbox: secret-looking files are masked at any depth (.env*, *.pem, *.key, id_rsa, id_ed25519, authorized_keys), not only .env* at the workspace root. sub/.e''nv and server.pem were readable through bash.
  • Env: bash now gets an allowlisted environment instead of a denylist. DATABASE_URL, *_WEBHOOK, STRIPE_* and custom *_KEY variables leaked before. Opt back in with TETHER_ENV_PASSTHROUGH=A,B.
  • Web: web fetch blocks loopback, private, link-local and cloud-metadata addresses, checked on every redirect hop (TETHER_WEB_ALLOW_PRIVATE=1 to opt out).

Features

  • Sandbox: optional network isolation, tether run|pipeline --no-network / SandboxPolicy(network=False) mapping to bwrap --unshare-net. Sub-agents and stages can only keep or narrow it; without bwrap it fails closed. (#23)

Fixes

  • Sandbox: the fallback command guard no longer rejects awk/sed/grep/perl program or pattern arguments that start with /. (#31)
  • Tools: unknown names in --tools / Harness(tools=...) now raise ValueError (CLI prints Error: ..., exit 1) instead of silently loading nothing. (#22)

v0.1.3 Bash Quoting & Structured History Replay

Choose a tag to compare

@igormcsouza igormcsouza released this 18 Oct 15:28
59f974a

Fixes

  • Bash quoting (#37, PR #42): the bash tool now receives the original command text instead of a shlex.split then " ".join rebuild, so quotes survive (sed -i 's/a b/c d/' f, grep -n "return list" f, python -c "print(1+1)") and pipelines, && and ; keep working. Previously any quoted argument with spaces or parentheses was re-split by the shell.
  • History replay (#38, PR #43): past actions are now replayed to Ollama, OpenAI-compatible and Anthropic providers as real tool_calls plus tool results (tool_use/tool_result on Anthropic) instead of act('...') assistant text, which small tool-calling models copied into real arguments and corrupted files. Replayed stdin is a real 400-char prefix, not a copyable <N chars> placeholder. Custom providers keep the textual form unless they set structured_history = True. The system prompt and tools array are unchanged.

Docs

  • New runnable example examples/course/ and a Troubleshooting page (symptom, cause, fix, known limitations); @tool argument parsing, the tools.py plus tools: requirement, gate and pipeline practices, observation-folding workarounds, Ollama in Docker and the awk/sed sandbox false positive.

Verified

End-to-end on qwen3-coder:30b (bug-fix task on a small FastAPI repo): 18 steps, one-line fix, all tests pass, no corrupted arguments. Before these fixes the same task failed in five attempts.

v0.1.2 Small-Model Tool Args & Literal Newline Fixes

Choose a tag to compare

@igormcsouza igormcsouza released this 18 Oct 01:51
ed30666

Fixes

  • @tool argument parsing (#25): extra unquoted words now join into the last positional str parameter even when later parameters are optional non-str (yt-search arquitetura em camadas with def yt_search(query: str, limit: int = 3)); later optionals are set via --flag. *args: str parameters now receive the words splatted instead of failing with unexpected keyword argument.
  • Multiplexer (#26): small models that send edit write/edit replace stdin or the done deliverable as one line with literal \n/\t escapes now get them unescaped deterministically (only when the stdin has no real newline). bash stdin and all other tools are never touched.

Behavior note: an optional positional after a str param can no longer be set positionally; use --flag.

Open design questions for v0.2: #24 (skill tools.py registration), #27 (observation folding with small models).

v0.1.1 Silent-Success Bash Fix, tether --version & v0.1 Feature Tutorial

Choose a tag to compare

@igormcsouza igormcsouza released this 18 Oct 00:32
dc5df37

Tether v0.1.1

🛠️ Fixes

  • Bash: a command with no output now returns [exit 0: no output] Command succeeded. instead of a bare [exit 0], which 9B models misread as failure and repeated until the loop breaker fired (0 loop stalls in a real gemma4:e4b run).
  • CLI: added the documented-but-missing tether --version.

📚 Documentation

  • New tutorial page: verification gates (--verify), done --ask, project memory (mem --project), YAML pipelines, tether stats and tether retro.

📦 Install

pip install tether-sdk / uv add tether-sdk (PyPI) · Docs: https://igormcsouza.github.io/tether/

Full changelog: v0.1.0...v0.1.1

v0.1.0 Verification Gates, Pipelines, Telemetry, Project Memory & Retro

Choose a tag to compare

@igormcsouza igormcsouza released this 18 Oct 00:19
0e43950

Tether v0.1.0

🚀 Milestone v0.1: Deterministic Control Plane

  • Pre-done Verification Gates: Harness(verify=[...]), --verify, or Skill verify: run inside the session SandboxPolicy before done can complete a session (0 static prompt tokens until a gate fails).
  • Interruptible WAITING_INPUT & done --ask: sessions pause for human/parent input and resume via tether send.
  • Hierarchical Project Memory: mem pin --project / mem search --project with cross-session BM25 RAG.
  • Telemetry & Failure-Mode Inspector (tether stats): per-model pass rate, token cost, step latency and ACI friction offenders.
  • Deterministic Multi-Stage Pipelines (tether pipeline): isolated stage sessions, heterogeneous model routing, monotonic sandbox attenuation, ~50-token stage handoffs.
  • Post-Mortem Distillation (tether retro): distills a session's friction trace into at most 2 short rules in SKILL.md (or project memory), offline only.

🛡️ Fixes from release validation

  • Sandbox: under bwrap, .env*, .tether/, .git/config and .git/hooks are masked at the mount level (previously bypassable via globs/shell indirection); PID/IPC namespaces unshared; SSH_AUTH_SOCK scrubbed.
  • tether stats: pipeline root sessions no longer double-count tokens or invent a model run.
  • CLI: invalid pipeline manifests and send to unknown sessions print Error: ... instead of a traceback.
  • Multiplexer: unknown command hints bash <cmd> when bash is enabled.

📦 Install

pip install tether-sdk / uv add tether-sdk (PyPI) · Docs: https://igormcsouza.github.io/tether/

Full changelog: v0.0.3...v0.1.0

v0.0.3 L1 Head+Tail Elision, Loop-Stall Breaker, KV-Cache Pooling, MkDocs & PyPI (tether-sdk)

Choose a tag to compare

@igormcsouza igormcsouza released this 17 Oct 12:17

Tether v0.0.3

🚀 Architectural & Performance Upgrades

  • Head + Tail L1 Active Observation Elision (tether/context.py): Oversized active observations (> 2,400 chars) are deterministically elided in L1 working memory to their first 900 chars (headers/command summary) + last 900 chars (stack trace/exit code) with a pointer to mem recall / mem search, preserving full outputs in SQLite FTS5.
  • Deterministic Loop-Stall Breaker (tether/harness.py): Consecutive identical (cmd, stdin) calls from small 8B/9B models are intercepted before tool execution and answered with a deterministic [LOOP DETECTED] recovery nudge.
  • 100% KV-Cache Prefix Immutability Across Pins (tether/context.py, tether/providers/anthropic.py): [PINNED MEMORY] is attached to the tail message after window trimming so earlier turn messages remain 100% byte-identical when pins change; added Anthropic ephemeral cache_control breakpoints.
  • Persistent Connection Pooling & Thread-Local SQLite WAL (tether/providers/*, tether/store.py): Reuses persistent httpx.AsyncClient instances across turns and caches thread-local SQLite WAL connections with PRAGMA temp_store=MEMORY; and 128 MB mmap_size.

📦 Packaging, Documentation & CI

  • Published on PyPI (tether-sdk): Install via pip install tether-sdk, uv add tether-sdk, or uv tool install tether-sdk (https://pypi.org/project/tether-sdk/).
  • Flattened Package Layout: Moved tether/ to the repository root (removed src/).
  • MkDocs Documentation Site: Full tutorials, architecture & literature review, and auto-generated API reference live at https://igormcsouza.github.io/tether/.
  • Per-Module Test Suite & 100% Coverage CI Gate: Split unit tests into 20 per-module test files under tests/ and enforced ruff, mypy, mkdocs build --strict, and pytest --cov=tether --cov-fail-under=100 in CI.