Amp Runner
Below is the implementation spec for the AMP CLI (Sourcegraph) runner shipped in Untether.
Deprecated
The
ampengine is deprecated and no longer supported (as of v0.36.0): it still loads, but gets no fixes, is excluded from testing, and may be removed in a future release. The integration is unmaintained, and AMP remotely refuses out-of-date clients with426and exits 1. The AMP-only/threadscommand is deprecated with it (#458).
Below is the implementation spec for the AMP CLI (Sourcegraph) runner shipped in Untether.
Scope
Goal
Provide the amp engine backend so Untether can:
- Run AMP non-interactively via the AMP CLI (
amp). - Stream progress by parsing
--stream-jsonoutput. AMP uses a Claude Code-compatible JSONL protocol. - Support resumable sessions via
amp threads continue <thread-id>.
Non-goals (v1)
- Full thread management — only the deprecated AMP-only
/threadscommand (list, search, view, resume, archive) is exposed via Telegram;shareand the rest are not.
UX and behavior
Engine selection
- Default: use
default_enginefrom config - Override:
/amp <prompt>in Telegram
Resume UX (canonical line)
Untether appends a single backticked resume line at the end of the message:
`amp threads continue T-2775dc92-90ed-4f85-8b73-8f9766029e83`
Notes:
- The resume token is the thread ID (format:
T-<uuid>), captured from thesystem(init)event’ssession_idfield. - AMP calls sessions “threads” —
amp threads continueresumes them.
Non-interactive runs
The runner invokes:
amp [--dangerously-allow-all] [--mode <mode>] --stream-json [--stream-json-input] -x <prompt>
Flags:
--dangerously-allow-all— auto-approve all of AMP’s tool calls. Default flipped tofalsein v0.35.3 (#206); set[amp] dangerously_allow_all = trueto enable.--mode <mode>— optional (deep|free|rush|smart), from[amp] mode; a/configmodel override is passed as--mode- No
--modelis passed:[amp] modelonly labels the🏷footer when no mode is set -x— execute mode (non-interactive)--stream-json— JSONL output--stream-json-input— optional; enables stdin streaming (preliminary support, configurable)
Prompts starting with - are space-prefixed via sanitize_prompt() (base runner method) to prevent the CLI from interpreting the prompt as a flag.
For resumed sessions:
amp threads continue <thread-id> [--dangerously-allow-all] [--mode <mode>] --stream-json [--stream-json-input] -x <prompt>
Config additions
untether config
untether config set default_engine "amp"
untether config set amp.model "claude-sonnet-4-6"
untether config set amp.mode "smart"
untether config set amp.dangerously_allow_all false
toml
# ~/.untether/untether.toml
default_engine = "amp"
[amp]
model = "claude-sonnet-4-6" # optional; footer label only (not passed to amp)
mode = "smart" # optional; deep|free|rush|smart
dangerously_allow_all = false # default: false (changed in v0.35.3 #206)
stream_json_input = false # default: false; passes --stream-json-input
Notes:
modecontrols model selection, system prompt, and tool availability within AMP.dangerously_allow_alldefaults tofalseas of v0.35.3 (#206) — opt in only if you specifically want AMP runs without its built-in permission system. Untether’s own permission layer remains the primary control.stream_json_inputenables--stream-json-inputfor stdin streaming. Nothing reads it back: approvals, plan mode, AskUserQuestion, live sessions and steer are Claude Code-only.
Code changes (by file)
src/untether/runners/amp.py
Exposes BACKEND = EngineBackend(id="amp", build_runner=build_runner, install_cmd="npm install -g @sourcegraph/amp").
Runner invocation
amp [threads continue <thread-id>] [--dangerously-allow-all] [--mode <mode>] --stream-json [--stream-json-input] -x <prompt>
Event translation
AMP uses a Claude Code-compatible JSONL protocol with a type discriminator. The runner translates:
system(subtype="init")->StartedEvent(captures session_id)assistant(tool_use blocks) ->ActionEvent(phase: started)user(tool_result blocks) ->ActionEvent(phase: completed)assistant(text blocks) -> text accumulation for final answerresult->CompletedEvent(with accumulated usage)
Subagent tracking
parent_tool_use_id from assistant/user messages is stored in action.detail["parent_tool_use_id"] when present. This tracks which tool calls belong to subagent invocations.
Usage accumulation
Unlike Gemini (which reports usage once in result.stats), AMP reports per-message usage in assistant messages. The runner accumulates input_tokens and output_tokens across all assistant messages and builds the final usage dict at completion.
Installation and auth
Install the CLI globally:
npm install -g @sourcegraph/amp
Run amp login to authenticate with Sourcegraph.
Known pitfalls
- AMP uses
amp threads continue <thread-id>for resume, not--resume. - Thread IDs use the format
T-<uuid>(e.g.,T-2775dc92-90ed-4f85-8b73-8f9766029e83). --stream-json-inputis passed whenstream_json_input = truein config. No approve/deny flow is wired for AMP; interactive features are Claude Code-only.- Untether does not pass
--model; model selection is controlled server-side by--mode.
See also
- Error Reference — actionable hints for common engine errors