Skip to main content
Reference Last updated: 26 May 2026

Amp Runner

Below is the implementation spec for the AMP CLI (Sourcegraph) runner shipped in Untether.

Nathan Schram
By Nathan Schram Founder, Little Bear Apps

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-json output. AMP uses a Claude Code-compatible JSONL protocol.
  • Support resumable sessions via amp threads continue <thread-id>.

Non-goals (v1)

  • Thread management commands — amp threads list/search/share etc. are not exposed via Telegram.

UX and behavior

Engine selection

  • Default: use default_engine from 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 the system(init) event’s session_id field.
  • AMP calls sessions “threads” — amp threads continue resumes them.

Non-interactive runs

The runner invokes:

amp [--dangerously-allow-all] --mode <mode> --model <model> -x --stream-json <prompt>

Flags:

  • --dangerously-allow-all — auto-approve all of AMP’s tool calls. Default flipped to false in v0.35.3 (#206); set [amp] dangerously_allow_all = true to enable.
  • --mode <mode> — optional (deep|free|rush|smart)
  • --model <model> — optional, from config or /config override
  • -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] -x --stream-json <prompt>

Config additions

=== “untether config”

```sh
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”

```toml
# ~/.untether/untether.toml

default_engine = "amp"

[amp]
model = "claude-sonnet-4-6"       # optional; passed as --model
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:

  • mode controls model selection, system prompt, and tool availability within AMP.
  • dangerously_allow_all defaults to false as 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_input enables --stream-json-input for stdin streaming. This is preliminary plumbing — the interactive control flow (approve/deny via Telegram) is not yet wired.

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>] [--model <model>] -x --stream-json [--stream-json-input] <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 answer
  • result -> 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-input is passed when stream_json_input = true in config. The interactive control flow (approve/deny buttons in Telegram) is not yet wired — this is preliminary plumbing.
  • AMP’s --model flag may have no effect when using hosted models (model is controlled server-side by --mode).

See also

Was this helpful?

Related Articles