Prompts, policy, providers, state, and the TUI live in this repository.
Dext — Technical Documentation
Dext is a single-binary Rust coding agent that runs from your terminal. It keeps project-scoped session state and gives the model a curated set of native tools for filesystem operations, search, shell execution, data processing, HTTP requests, Git operations, and task tracking.
Dext is source-first: prompts, runtime state, tool policies, provider wiring, and the TUI all live in the repository with no external service required beyond your chosen model provider.
--resume or a session command. recall.md is bounded agent working memory: project DEXT.md policy decides whether the agent maintains it, and every native write stays inside normal tool approval, mutation preview, checkpoint, 4 KiB size, and privacy-redaction controls. Seat summaries are user-authored context; --no-session disables durable session/log writes.docs/ after each reviewed change to main. Focused Markdown guides remain supplemental. Open non-documentation risks are tracked in the risk register.cargo fmt --all -- --check, Clippy with warnings denied, cargo audit --deny warnings, cargo deny check licenses, the vendored ratatui-core tests, release build/tests, and the PTY smoke suite. Reinstall with cargo install --path . --force --locked so the binary on PATH matches the source. Renderer-specific requirements are documented in docs/TUI.md.dext --sandbox-profile danger-full-access --approval always. Dext adds no confinement and uses ambient authority inside the current host, container, VM, namespace, WSL environment, CI worker, remote shell, or service account; it neither requires nor escapes those boundaries. Optional workspace-write, read-only, and prompting approval profiles remain available.Architecturally, Dext uses Agent in main.rs as a facade around focused modules: provider request shaping and auth (provider.rs), bounded stream assembly (streaming.rs), tool-round execution and side-effect fencing (tool_round.rs, tool_journal.rs), tool schemas and policy (tools.rs, tool_policy.rs), project/session state (session.rs), interactive rendering (tui.rs), safety/recovery primitives (git_checkpoints.rs, mutation_preview.rs, sandbox.rs), and extension metadata/runtime (packs.rs, shelves.rs, orchestrator.rs).
Quick Start
Install on Linux or macOS
curl --proto '=https' --tlsv1.2 -LsSf https://raw.githubusercontent.com/SiliconState/Dext/main/scripts/install.sh | sh
Install on Windows PowerShell 5.1 or PowerShell 7
irm https://raw.githubusercontent.com/SiliconState/Dext/main/scripts/install.ps1 | iex
The Windows installer derives the native architecture from Windows environment values rather than nullable modern-.NET runtime metadata, so the same in-memory script works under Windows PowerShell 5.1 and PowerShell 7. The installers require an exact vX.Y.Z tag, select the matching release archive, verify its SHA-256 checksum, reject an existing destination that is not a regular non-link/reparse file, and validate that the candidate starts and reports the selected version before replacing the current-user binary from a same-directory staged file. Unix uses an atomic same-filesystem rename. Windows uses File.Replace when supported; an explicitly unsupported operation falls back to same-directory renames, restores the previous binary if installing the staged candidate fails, and retains a recovery backup named in the error if rollback itself fails. They can additionally require GitHub provenance verification with DEXT_REQUIRE_ATTESTATION=1. Dext v0.1.0 is published, so the default installers download prebuilt archives and do not require Rust. If no tagged release is available, both installers can resolve and pin the current main commit before running a locked Cargo build; set DEXT_SOURCE_FALLBACK=0 to refuse that fallback. Because source builds have no release attestation, attestation-required mode also disables source fallback. Review the scripts locally before running them if you prefer a review-first install; use the release guide for provenance and SBOM verification.
Authenticate
dext auth providers # list available providers
dext auth login chatgpt # ChatGPT/Codex OAuth
dext auth login glm # paste the ZAI key at Dext's prompt
dext auth login openai # paste the OpenAI key at Dext's prompt
dext auth login kimi # paste the Kimi key at Dext's prompt
Run
dext # interactive session
dext "summarize this repo" # one-shot
dext --frugal --effort off # low-token mode
Project Layout
| File | Purpose |
|---|---|
src/main.rs | Agent loop, provider HTTP, permissions, slash commands, CLI entry, eval |
src/main_tests.rs | Unit and integration tests for main.rs |
src/tui.rs | Ratatui inline TUI, permission prompts, transcript rendering |
src/provider.rs | Provider catalog, API-key and provider-specific OAuth auth, request shaping, model normalization |
src/claude_subscription.rs | Version-pinned Claude subscription billing/checksum/identity wire compatibility for official Anthropic OAuth requests |
src/sse.rs | Input-buffer-bounded SSE frame decoder shared by runtime and benchmarks |
src/streaming.rs | Provider event validation and stream/tool-call assembly |
src/tool_round.rs | Tool planning, approval, checkpoint/journal boundaries, dispatch, result normalization |
src/tool_journal.rs | Owner-private side-effect start/terminal records and resume reconciliation |
src/session.rs | Session/log persistence, project state locks, atomic I/O |
src/seats.rs | Project-scoped durable agent identities and seat-specific latest-session lookup |
src/sandbox.rs | Optional OS confinement, profile write roots, and private scratch; full access follows a direct ambient-authority path |
src/tools.rs | Tool definitions, permission metadata, parallel-safe classification |
src/orchestrator.rs | Work phases, similarity guards, objective tracking, adaptive caps |
src/git_checkpoints.rs | Git-native recovery refs, /undo, sidecar files, pruning |
src/mutation_preview.rs | In-memory line-level previews before applying file mutations |
src/packs.rs | Pack discovery, invocation, conversational pack inference |
src/shelves.rs | Typed shelf registry with ability metadata, signals, and effects |
src/tool_policy.rs | Command risk classification, input validation, bash guardrails |
src/privacy.rs | Privacy policy, sensitive-path/search-scope denial, secret/PII redaction |
src/usage.rs | Token usage normalization, per-model pricing, budget caps |
src/events.rs | AgentEvent stream and the EventSink front-end trait |
src/crash.rs | Panic hook, redacted owner-only crash snapshots, event breadcrumbs |
src/process_tree.rs | Child session detachment and whole-tree teardown |
src/secret_redactor.rs | Streaming credential scrubbing for child-process output |
scripts/install.sh / install.ps1 | Per-user checksum-verifying release installers with an exact-revision locked source fallback when no tagged release is available |
scripts/test_install.sh / test_install.ps1 | Offline platform-native installer regressions for replacement, no-clobber failures, strict tags, safe destinations, source pinning/fallback disablement, malformed API state, version mismatch, and attestation-required paths; Windows PowerShell 5.1 and PowerShell 7 both execute the complete harness and an in-memory Invoke-Expression install matching irm | iex, plus forced unsupported replacement, rollback, and retained-backup recovery |
deny.toml | Dependency-license allowlist enforced by security and release workflows |
benches/dext_bench.rs | Criterion performance harness |
tests/tui_smoke.rs | Unix PTY-backed launch, multiline input, streaming, and resize regression tests |
tests/tui_smoke_windows.rs | Windows ConPTY-backed harness self-checks plus real-binary launch, input, default-policy status, exit, and terminal-restoration smoke test |
vendor/ratatui-core/ | Exact upstream source plus Dext's narrow inline-terminal compatibility patch |
Architecture
Dext follows a single-binary architecture with no runtime plugin service. The Agent facade composes prompts and state while focused modules assemble provider streams, execute tool rounds, enforce policy, render the terminal, and persist recovery metadata.
High-Level Data Flow
User Input → Agent Loop → Provider HTTP (streaming SSE)
↓
Response Blocks (text/thinking/tool_use)
↓
Tool Dispatch → Execute → Result
↓
Append to History → Next Turn
↓
Compaction (if context pressure)
System Diagrams
This section documents executable runtime behavior with HTML-native SVG diagrams. The shapes map to Rust modules and runtime checkpoints instead of being merely illustrative.
Turn Loop Sequence — user input to next turn
Tool Execution Sequence — validation, preview, approval, checkpoint, result
write_file, edit_file, and multi_edit render their diff before the approval prompt, and the approved executor reuses that same prepared mutation.read_file, rg, git_diff, etc.) parallelize; checkpoints stay on the sequential dispatch boundary.Checkpoint Lifecycle — Git recovery before mutation
Turn Loop Flowchart — branch points
Checkpoint Restore Flow — preview vs apply
HEAD requires the explicit reset-head mode.Key Enums and Structs
| Type | Defined In | Purpose |
|---|---|---|
ThinkingEffort | main.rs | Reasoning depth: Off, Minimal, Low, Medium, High, XHigh, Max |
ReasoningMode | main.rs | Independent Standard or Pro execution mode; active only for official OpenAI GPT-5.6 Responses requests |
OutputMode | main.rs | Text, Json, StreamJson — output format for non-interactive mode |
ApprovalProfile | main.rs | Ask, AutoRead, AutoWrite, Never, Always — permission gating |
SandboxProfile | main.rs | ReadOnly, WorkspaceWrite, DangerFullAccess |
ContextMode | main.rs | Standard, Frugal — context window management |
MutationPreviewMode | main.rs | Off, Simple, Git — diff preview before mutations |
Usage | usage.rs | Token tracking: input, output, cache_create, cache_read |
BudgetCap | usage.rs | Session budget limits in USD or tokens |
WorkLedger | main.rs | Objective, phase, decisions, pending/done/blocked items |
SessionHeader | main.rs | Persisted session metadata with full provenance |
Message / Block | main.rs | Conversation history: Text, Thinking, ToolUse, ToolResult |
AgentEvent | events.rs | Event stream: TurnStart, TextDelta, ToolCallResult, etc. |
Main.rs — Agent Core .rs
main.rs owns the Agent facade, CLI and slash-command dispatch, prompt/context assembly, compaction, built-in tool adapters, and eval harness. Provider stream parsing lives in streaming.rs; tool planning and dispatch live in tool_round.rs; durable side-effect records live in tool_journal.rs.
The default policy is approval always with sandbox profile danger-full-access; a no-argument run is equivalent to passing both flags explicitly. Full access adds no Dext confinement and uses ambient authority inside the current host, container, VM, namespace, WSL environment, CI worker, remote shell, or service account without attempting escape. Current-run policy overrides saved provenance on resume. Approval and sandbox dimensions remain independent, and ask, auto-read, auto-write, never, read-only, and workspace-write remain available. The last CLI policy flag takes precedence over environment configuration. Invalid approval environment values warn and fall back to ask unless a valid higher-precedence choice or true DEXT_TRUST supplies a policy; an invalid DEXT_SANDBOX_PROFILE fails normal startup instead of silently selecting full access.
Agent Loop
The central Agent struct drives a turn-based loop:
- Prompt composition — Builds the system prompt from a compact invariant-driven built-in agent policy plus
DEXT.md, project context, tool catalog, session header, work ledger, shelf abilities, and recall working memory. The standard built-in prompt is compact; tool-specific syntax stays in lean schemas instead of being duplicated in universal prose. Composition splits into a cached stable block and a volatile environment tail that rides after the cache breakpoint. Turn-stable sections — project guidance, recall, and the pack and shelf registry summaries — stay in the cached block; context-file cache identity includes size/time plus file identity/change metadata where the platform exposes it, and mutation-capable tool rounds and approved hooks invalidate pack discovery before the next request. The model-visible environment retains actionable cwd/OS/Git, provider/model/effort/context, approval, sandbox, session id, UTC date, and privacy state; variable string values are byte-bounded and unsafe whitespace/control content is JSON-quoted onto one line, while persisted ledger/provider-health strings are collapsed and bounded before rendering. It omits toolset/schema labels already evident from provider tool definitions and host-only compaction thresholds. Context strategy budgets are omitted before the first tool action, when every counter would only repeat zero state, then remain explicit after actions so reset, warning, pattern, and pivot signals are preserved. Each ancestorDEXT.md/recall.mdinput is limited to a regular non-symlink file of at most 1 MiB; recall content is privacy-redacted and receives one aggregate 4 KiB payload budget across ancestry before prompt injection. Provenance paths and raw-file hashes come from the same bounded reads actually considered for the prompt. Aggregate project-context and per-section caps include headings or truncation markers as applicable, and wholly omitted files are excluded from prompt provenance. Todo state is limited to 256 KiB across tool, prompt-summary, and TUI loading paths. Only per-round state (work ledger, context state, provider health, todos, shelf context) is re-sent at full input rate. Standard and frugal tail caps come from one table and differ only in cap values and hint wording. - History management — Maintains a
Vec<Message>with automatic compaction when context pressure exceeds configurable thresholds (default: 90% at end-turn, 80% after safe tool-result checkpoints). - Provider dispatch — Sends streaming requests to the active provider. Applies connect, first-byte, and between-chunk idle deadlines, then parses bounded SSE frames into
Blockvariants. - Tool execution — Dispatches
tool_useblocks to native Rust implementations. Supports parallel execution for read-only tools. The round waiter observes interrupts independently of task completion, aborts in-flight tasks, and prevents a call that wins its concurrency permit after the interrupt from starting; every abandonedtool_useid still returns a matching interrupted result. Native file/todo reads check cancellation between bounded chunks; explicitread_filelimits stop after detecting additional data, andread_symbolsource input is capped at 8 MiB. - Permission gating — Routes tool calls through
EventSink::request_permission()based on the activeApprovalProfileand tool risk classification. - Steering — Active-turn user input is routed to a steering channel, injected at safe boundaries.
Stream Parsing
| Provider | API | Request Builder |
|---|---|---|
| Anthropic / GLM / Kimi Code | Messages API (/v1/messages) | Request struct with AnthropicThinking |
| Official OpenAI GPT-5.6 / explicit custom Responses profiles | Responses API (/v1/responses) | build_openai_responses_request(); official GPT-5.6 adds independent reasoning.effort and reasoning.mode |
| Other OpenAI / DeepSeek / Local | Chat Completions (/v1/chat/completions) | OaiRequest with provider-compatible reasoning_effort |
| ChatGPT / Codex | Codex Responses API (/codex/responses) | build_chatgpt_request(); no Platform-only mode field |
Transport Deadlines and Body Bounds
The shared provider client uses a 15-second connect timeout. Cloud requests allow 180 seconds to first response headers and 90 seconds between stream chunks; local llama.cpp requests default to 600 seconds and 300 seconds respectively. DEXT_PROVIDER_CONNECT_TIMEOUT_SECS, DEXT_PROVIDER_FIRST_BYTE_TIMEOUT_SECS, and DEXT_PROVIDER_STREAM_IDLE_TIMEOUT_SECS accept positive overrides. Initial requests and compaction retries use the same first-byte policy. Non-stream compaction responses use the stream-idle deadline while reading and reject JSON bodies above 4 MiB; provider error diagnostics stop at 4,000 bytes, and an empty summary error does not echo the raw provider body or hidden reasoning. A ChatGPT Responses finalize error caused by malformed function arguments is never executed; if no visible text was streamed, Dext compacts once when a safe split exists and retries exactly once, then surfaces the protocol error if it persists.
src/sse.rs limits its in-progress input buffer to one configured event plus at most four delimiter bytes before rejection. One large network read may still contain many valid small events; the decoder drains complete frames incrementally rather than rejecting by chunk size.
Responses terminal events with status=incomplete are recoverable rather than fatal protocol errors. Dext executes only function calls that reached a streamed completion event and discards truncated calls, ignoring complete-looking terminal snapshots for those unfinished calls. Discarded live text/thinking preview state is reset; a content-filter terminal also discards function calls and opaque encrypted reasoning state. Interactive warnings identify the recovery. If no executable call remains, Dext issues a bounded continuation request with a concise runtime hint; provider-reported content filtering halts immediately instead of retrying. Recovery lowers reasoning effort for that request only (for example, xhigh to medium) without changing the user-selected effort or consuming the normal tool-iteration budget. After three unsuccessful continuation requests, Dext halts the turn with guidance while keeping the session usable. Responses-based compaction summaries likewise reject text from incomplete terminals, retry within the existing four-attempt summary stream budget, halt immediately on content filtering, and accumulate usage from every parsed attempt. Stream protocol errors raised inside a response.incomplete terminal event (missing or self-conflicting response objects) classify as transient backend truncation and retry within the bounded stream-attempt budget instead of failing the turn permanently.
Anthropic Messages streams that emit message_stop while text or thinking blocks remain open close those display blocks implicitly and emit their block-complete updates. Tool-use blocks are stricter: a call that never received content_block_stop is never executable, even when its buffered argument JSON looks complete. An explicitly stopped tool-use block cut off mid-JSON at stop_reason=max_tokens is also discarded, but only when the JSON parser reports an EOF-shaped incomplete value; malformed non-EOF JSON and complete non-object arguments remain precise finalize errors. Dext surfaces discarded calls as unfinished, preserves and executes any earlier explicitly completed calls in the same message, and when none remain issues the same bounded automatic continuation used for Responses incomplete recovery (up to three recovery requests, then a halt notice that keeps the session usable).
Official OpenAI GPT-5.6 uses stateless Responses requests with store:false. Tool-bearing requests explicitly include reasoning.encrypted_content; when the provider returns a valid opaque reasoning item, Dext retains it in session history and replays it only within the current user/tool turn. Older-turn reasoning and malformed or placeholder items are omitted. ChatGPT/Codex input continues to omit persisted reasoning items. OpenAI Responses tools use the flat function shape with strict:false; ChatGPT/Codex tools retain their existing flat strict:null shape.
Session Persistence
Sessions are stored as JSONL files under ~/.dext/projects/<project-key>/sessions/. The first line is a SessionHeader with full provenance. Plain unseated writes retain format v3 and Seat-only writes use v4 for backward compatibility; runtime-bearing writes use v5 so pre-runtime binaries reject rather than ignore executable-runtime state. Valid transitional v3 Seat headers remain loadable and validated, then upgrade on the next Seat-only save; v1–v2 cannot carry Seat metadata, and v1–v4 cannot carry nonempty runtime metadata. Header serialization and reads are bounded at 256 KiB. Invalid persisted accounting metadata is rejected instead of affecting resumed enforcement. Runtime restoration preserves current-run approval/sandbox policy and preflights project trust, exact canonical pack-directory/source identity, manifest/hash/state accounting, and current executable approval before applying any saved sandbox/model/session fields; failure does not partially mutate the live agent. Session review remains available through list, brief, analyze, grep, failure, verification, and decision views. Export writes an explicit HTML or JSONL copy. Prune removes stale locks and lock-only project trees while preserving session JSONL, Seats, and other project state.
Eval Harness
Outcome-oriented assertions on files and command output. The eval path validates objective completion semantically (not just command exit), runs model tools and verification commands under the resolved --sandbox/DEXT_SANDBOX_PROFILE policy, and records verification artifacts for later audit. Run via dext --eval [NAME] [--sandbox PROFILE].
Crash Recovery
A panic hook writes an owner-private JSON snapshot under ~/.dext/crashes/ with a generated crash id, hashed source-location metadata, terminal dimensions, process id, current generated session id, recent event breadcrumbs, and whether backtraces were enabled. Front-end sinks record each structural breadcrumb exactly once, including JSON and stream-JSON modes. Free-form panic payloads, raw source paths, environment text, and backtrace content are omitted.
Session.rs — Session & State .rs
Manages all persistent state for Dext sessions, logs, and project-scoped data.
State Directories
~/.dext/ # DEXT_HOME (overridable)
├── providers.json # Provider catalog
├── auth.json # Stored credentials (0600 on Unix)
├── .env # Optional user-owned Dext dotenv settings
├── settings.json # user compaction threshold settings
├── session-locks.operation.lock # owner-private cross-process session lock guard
├── crashes/ # owner-private crash snapshots
├── shelves/ # User-scoped shelves and packs
└── projects/
└── <project-key>/
├── seats/
│ └── <seat-id>/
│ └── seat.json # Bounded durable identity + latest session id
└── sessions/
├── <name>.jsonl # Named session export
└── <session-id>/
├── _latest.jsonl
├── latest.log
├── session.lock.json
├── DEXT.todo.json
├── tool-journal.json
├── artifacts/
├── git-auth/
└── sudo/
Project Key
Each project gets a stable key derived from its canonical path: <slug>-<FNV-1a-hash>. This ensures isolated state per project even with identical directory names.
Each project may contain bounded Seat records under seats/<seat-id>/seat.json. A Seat is a durable agent identity; a session is one transcript/crash-recovery incarnation. Portable lowercase ids are validated before path construction; trailing dots and Windows device names are rejected. Unix ancestors must be owner-safe, managed directories owner-private, and record files regular, private, single-link, and no-follow. Selecting --seat NAME does not create an empty record; the first successful durable save or explicit dext seat set persists it. Use dext seat set NAME --label TEXT, --summary-file PATH|-, --clear-label, or --clear-summary to maintain bounded context. --seat NAME --resume follows that Seat's latest-session pointer. Cross-Seat, same-name cross-project, malformed, oversized, and unprovenanced restoration fails before saved state mutation. --no-session --seat NAME is contextual only. Prompt-visible context is privacy-redacted JSON marked as user-authored data, not instructions, and the complete rendered Seat section is capped at 1,000 bytes in both context modes; persistent labels retain their independent 128-character validation cap. Project changes clear active identity. /reset serializes pointer update and transcript removal and attempts pointer rollback on deletion failure. Crew directly maps portable role names to crew.<agent> and assigns deterministic crew.agent-<hash> ids to other valid custom names; captured, detached, and pane workers pin one absolute Dext state root. Same-user replacement is outside Dext's isolation boundary; validation and atomic replacement remain correctness controls.
Atomic Writes
Sensitive state writes use a temp-file-and-replace helper. On Windows the replacement uses MoveFileExW; on Unix it uses fs::rename. Session logs normally use private append writes while they remain below the cap.
Session State Lock
Each active session directory has a session.lock.json record containing PID, token, project, sandbox, and session identity. Session open, stale reclamation, cleanup, and prune operations are serialized by the owner-private session-locks.operation.lock file under DEXT_HOME. Stale removal revalidates the token and PID while holding that lock, so a replaced live lock is preserved. Matching locks are released through a cleanup registry. dext session prune runs as a dry run unless --apply is supplied; it preserves every project directory containing session or other project state and removes only stale locks plus stale lock-only directory trees.
Log Rotation
Each session's latest.log is capped at 64,000 bytes. DEXT_LOG_ARCHIVES may retain up to 16 rotated archives; the default is zero.
Provider.rs — Provider Catalog .rs
Manages the catalog of model providers, authentication, request shaping, and model normalization.
ApiProvider Enum
Three wire-format families:
Anthropic— Anthropic Messages API (also used by GLM viaapi.z.ai/api/anthropic)OpenAi— OpenAI-compatible APIs. Ordinary models use Chat Completions; the built-in officialopenaiprofile routes GPT-5.6 atapi.openai.comthrough the Platform Responses API.ChatGpt— ChatGPT Responses API (OAuth-backed)
Built-in Providers
| ID | Display | API | Default Model | Auth |
|---|---|---|---|---|
glm | ZAI GLM | Anthropic | glm-5.2[1m] | API Key (ZAI_API_KEY); catalog also includes glm-5.3-flash and glm-5.3-flash[1m] with 1M context, 131,072-token output, multimodal capability metadata, and low/high/max effort |
chatgpt | ChatGPT | ChatGPT Responses | gpt-5.4 | OAuth (OpenAI auth) |
openai | OpenAI API | OpenAI | gpt-5 | API Key (OPENAI_API_KEY) |
anthropic | Anthropic | Anthropic | Provider catalog default | Claude Pro/Max OAuth via /login; API key via ANTHROPIC_API_KEY |
kimi | Kimi Code | Anthropic | k3 | API Key (KIMI_API_KEY) |
deepseek | DeepSeek | OpenAI | deepseek-chat | API Key (DEEPSEEK_API_KEY) |
local | Local llama.cpp | OpenAI | qwen3.6-35b-a3b-mtp-ud-q5_k_m | None; accepts the server model alias, probes live context, and defaults to frugal context |
Provider Resolution Chain
DEXT_PROVIDERenv varDEXT_PROFILEenv varDEXT_API_PROVIDERenv varactive_providerfield inproviders.json- Default:
glm
Model Resolution Chain
DEXT_MODEL_{PROVIDER}(provider-specific)DEXT_MODEL(withDEXT_MODEL_FORCEoverride)- Profile's
default_model
ChatGPT Model Normalization
Compact aliases are canonicalized (for example gpt5codex → gpt-5-codex and ChatGPT gpt-5.6 → gpt-5.6-sol). GLM models get an automatic glm- prefix when omitted, and model-name context hints such as [1m] are honored.
GPT-5.6 Responses Controls
The built-in OpenAI and ChatGPT catalogs include gpt-5.6-sol, gpt-5.6-terra, and gpt-5.6-luna; OpenAI also keeps the official unsuffixed gpt-5.6 Sol id, while ChatGPT normalizes it to gpt-5.6-sol. Compact aliases are gpt56/gpt56sol, gpt56terra, and gpt56luna. All variants declare 1,050,000-token context and 128,000-token output metadata.
For API-key OpenAI at the official endpoint, the four listed GPT-5.6 ids use /v1/responses; unknown gpt-5.6-* suffixes do not silently inherit that route. GPT-5.6 effort levels are none, minimal, low, medium, high, xhigh, and native max. Standard versus Pro is an independent model mode, defaults to Standard, and is carried inside the Responses reasoning object. Main turns and compaction summaries resolve effort through the selected model's advertised levels; unsupported selections clamp, and Off emits none only when advertised. Summaries preserve the selected Standard/Pro mode and receive Dext's reasoning-aware summary allowance whenever the summary model resolves a Responses reasoning effort, even when main-turn effort is Off. Tool-bearing stateless requests ask for opaque encrypted reasoning state so current-turn function-call continuation can replay it. DEXT_COMPACT_MODEL is normalized through the active provider; request contract, reasoning capability, effort levels, mode, and usage pricing come from the resolved summary model. This capability-scoped route does not change custom OpenAI-compatible endpoints or non-GPT-5.6 models.
ChatGPT OAuth retains its Codex Responses contract and GPT-5.6 levels from none through xhigh; Dext max maps to xhigh. It receives neither reasoning.mode nor max_output_tokens. Other built-in providers retain their prior model-specific request shaping.
Authentication
Credentials are stored in ~/.dext/auth.json. Two types are retained through runtime resolution: ApiKey (plain key, supports env var refs and !command secret references) and OAuth (access token + refresh token + expiry, used independently by ChatGPT and Anthropic subscription login). Provider/profile resolution merges built-ins with user catalog overrides while pruning retired bundled providers.
/login anthropic and dext auth login anthropic start an unofficial Claude Pro/Max OAuth flow; web forces replacement while retaining the existing credential until the new exchange succeeds. Only an OAuth credential on the built-in official Anthropic profile and endpoint activates the version-pinned Claude Code-compatible billing block, Agent SDK block, seeded checksum, beta/header, and UUID request/session shape. Anthropic API keys, GLM, Kimi, and custom profiles retain their ordinary request form; a stored Anthropic subscription credential combined with an overridden base URL or request contract fails closed rather than sending the OAuth token without its required wire shape. OAuth exchange and refresh use bounded, no-redirect requests and bounded JSON responses; long-running sessions re-check expiry before every user turn and persist refresh-token rotation without overwriting a newer credential. The loopback callback polls for new connections without blocking, switches each accepted connection to blocking I/O, and requires complete request headers within one two-second total deadline; it renders a lightweight Dext result page, but reports success only after exchange and secure credential storage complete; it includes no credential data and uses no-store/CSP response headers. The implementation is pinned to Claude Code 2.1.224 and must be revalidated when that private wire contract changes.
Tools.rs — Tool Catalog .rs
Defines all provider-visible tools and a shared ToolSpec registry for required fields, permission, side-effect/process, parallel-safety, and default/full-profile metadata. Static native tools and active pack-runtime tools first become provider-neutral {name, description, schema} descriptors, and the selected lean/full schema profile applies to both. Anthropic Messages, OpenAI Chat Completions, OpenAI Responses, and ChatGPT Responses adapters preserve those three fields while adding contract-required nesting, strictness, and cache controls. Empty tool collections are omitted from serialized requests, including summaries and models whose metadata disables tools. Lean schema stripping removes schema annotations without deleting arguments named description or literal data with that key. Policy code consumes registry metadata instead of repeating lists.
Tool Profiles
| Profile | Description | Schemas |
|---|---|---|
Full | Complete tool descriptions and full JSON schemas | Full |
Lean (default) | Compact action/safety/usage cues, schemas without field descriptions | Stripped |
Controlled via DEXT_TOOL_PROFILE. Lean mode saves significant prompt tokens per turn. A clean-repository fixture measures the real standard built-in prompt, a runtime tail with neutral provider/model placeholders, and deterministic normalized JSON for the default 13 lean {name, description, schema} descriptors; their total is capped below 6,000 bytes. This provider-neutral comparison payload is not an actual provider request, tokenizer count, billing count, formal canonical-JSON encoding, or universal maximum. The fixture separately reports actual tool-array bytes and a signed size delta from the normalized payload for Anthropic cache-on/cache-off, OpenAI Chat Completions, OpenAI Responses, and ChatGPT Responses. A separate toolset profile is selected by --toolset or DEXT_TOOLSET: default hides specialized tools and full exposes the complete catalog. Non-JSON startup emits [tools] toolset full whenever the full catalog is selected, including in frugal mode. Frugal mode applies smaller context/result/capture budgets without overriding explicit toolset or schema selections and uses the stricter pseudo-tool-protocol sanitizer described in the TUI section. The resolved live mode is passed through sequential and parallel tool rounds, so /context immediately controls subsequent native read captures and tool-result shaping. An explicit context choice remains pinned across provider switches and session restoration; without one, local providers select frugal and cloud providers select standard automatically. A valid CLI context mode takes precedence over a stale environment value, while an invalid DEXT_CONTEXT_MODE fails when no CLI override is supplied. The retired tiny mode and --tiny alias are rejected rather than silently mapped to frugal.
Tool Classification
| Category | Tools |
|---|---|
| Read-only (parallel-safe) | read_file, read_symbol, fd, rg, jq, fzf, git_diff, git_log, todo_read |
| Needs permission | bash, write_file, edit_file, multi_edit, http, awk, csvkit, git_commit, todo_write |
| External process | fd, rg, jq, fzf, awk, csvkit, git_diff, git_log |
Wire Format Adapters
provider_neutral_tools()— shared{name, description, schema}descriptors for static and active runtime toolswire_tools()— Anthropic Messages format with an optional final cache breakpointwire_tools_oai()— OpenAI Chat Completions nested function formatwire_tools_chatgpt()— ChatGPT flattened Responses format withstrict: nullwire_tools_openai_responses()— OpenAI Platform flattened Responses format withstrict: false
Pack and shelf management commands are separate from provider-visible tools. Packs act as modular battery packs: Dext creates, discovers, inspects, maintains, and invokes shelf-contained workflows through the existing approval and sandbox surface. Dext ships no pack content. A reviewed executable pack runtime may append validated dynamic tools only while active; those tools pass through the same provider-neutral descriptor layer and retain normal risk, approval, checkpoint, and session controls.
Tool_policy.rs — Risk & Guards .rs
Validates tool inputs, classifies command risk, and enforces bash guardrails.
Command Risk Levels
| Risk | Description | Examples |
|---|---|---|
Read | Read-only operations | ls, cat, native git_diff, http GET |
Write | Modifies files or state | write_file, edit_file, non-dangerous bash |
Danger | Destructive or sensitive operations; never auto-approved by auto-write | sudo, rm -rf, shell Git outside the explicit --no-pager metadata allowlist, inline/stdin interpreters, git push, HTTP POST/DELETE |
Bash Guardrails
- Auto-injects
set -o pipefailif missing. Because pipefail surfaces SIGPIPE from… | head-style truncation, exit 141 with captured stdout is classified as success (the raw exit line stays visible); exit 141 with empty stdout remains a failure. - Blocks
--break-system-packagespip flag (overridable) - Detects sudo commands needing password and routes them to the local auth prompt
- Classifies destructive Git worktree/ref/stash changes, per-command config overrides, and unknown aliases/subcommands as Danger. Because repository configuration can execute pagers, filters, fsmonitor, diff/textconv drivers, hooks, or aliases, shell Git is also Danger unless it uses explicit
git --no-pagerand matches a narrow helper-free metadata-inspection allowlist; commands such asgrep,diff-tree,ls-files,check-ignore, andcheck-attrremain gated because they can invoke fsmonitor. Use Dext’s hardened native Git tools for review operations. Inline or stdin interpreter execution—including shell input redirections and heredocs—and recognized dynamic or wrapper command paths are Danger because payload effects cannot be inferred safely. Dynamic command words include variable/command, glob, brace, tilde, and attached-redirection expansion forms. Actual shellcurl/wget/HTTPie/XH requests are gated because startup configuration and request bodies are not safely inferable; use the nativehttptool for read requests. Attached/clustered flags and common versioned Python/PyPy/Perl/Node/Ruby/PHP launchers are recognized. Python-vremains verbose and does not suppress stdin detection; Windows.exe/.comcommand and wrapper matching is case-insensitive. - Bash calls are atomic: Unix roots run in detached sessions/process groups; Windows roots start suspended, enter kill-on-close Job Objects, then resume. Dext cleans the full child tree after completion, timeout, interrupt, or cancellation/unwinding that drops an in-flight process-tree guard.
- On Windows, shell-backed tools skip Windows/WSL app aliases and select a real
bash.exefromPATH(for example Git for Windows);DEXT_BASH_PATHprovides an explicit override. - Advisories: prefer
rgovergrep -r, preferfdoverfind. Native-tool advisories only reference always-exposed tools (rg,fd); optional catalog tools such asjqare never advised as native replacements because lean sessions do not expose them.
Input Validation
Every tool call is validated for required fields before execution. Missing/empty required fields, type mismatches, numeric range violations, and mutually exclusive params are caught early with descriptive errors. Search extra_args reject positional and operand-changing forms, including attached ripgrep -ePATTERN/-fFILE, so model-supplied pattern/path fields remain the only search operands.
Auth Failure Detection
Tool output is scanned for auth failure markers (unauthorized, 401, 403, invalid api key) to trigger circuit breakers and prevent repeated credential burn on failing hosts.
Tui.rs — Terminal UI .rs
An inline TUI built on Ratatui + Crossterm that renders in the regular terminal buffer and uses native terminal scrollback during ordinary operation. On every effective transcript-pane width change, Dext immediately replaces stale-width scrollback with a complete replay of its logical transcript at the observed width. The backend output viewer is the only alternate-screen surface.
Layout
- Transcript area — Scrollable message history with user, assistant, tool, thinking, and steering lines
- Live status bar — Provider, model, thinking effort and selected
/promode when applicable, approval profile, context pressure, usage stats - Input panel — Multi-line text input with history (200 entries), completion for canonical handled slash commands, and argument hints
Startup Welcome
The startup welcome remains inline transcript content, so it scrolls away naturally with the conversation. One transcript-owned blank separator row keeps it visually distinct from CLI approval and sandbox diagnostics, including after inline viewport placement or replay. Its brand row shows Dext and the version, plus the working directory and cached Git branch/state at 80 columns or wider; narrower terminals drop that right segment. Exactly two facts, Model and Approval, sit between horizontal rules, followed by one rotating tip selected from verified commands and key bindings. Terminal-cell width controls alignment and path truncation. Git status uses one git status --porcelain=v1 --branch probe off the render loop, with only an 8 ms startup wait before path-only fallback. The empty composer reads ❯ Type a request… @ files · / commands.
Permission Prompts
Tool calls requiring permission render the pending prompt inside the inline viewport (with risk tier color coding: yellow for Read/Write, red for Danger), not into terminal scrollback. Choices: Once, Always (session), Deny. Only the compact decision line is appended to the transcript once resolved. Because inline scrollback is append-only, this keeps approvals from re-emitting (and therefore duplicating) the full history that older builds produced for the prompt spotlight and prompt-to-result swap.
Key Bindings
| Key | Action |
|---|---|
Enter | Submit input |
Shift+Enter / Alt+Enter | Insert newline |
Ctrl+O | Toggle the latest expandable tool output |
Ctrl+B | Open backend output viewer while bash runs |
Ctrl+L | Open the read-only current todo list without entering the alternate screen |
Ctrl+D | Quit |
Ctrl+C | Interrupt current turn |
Up/Down | Navigate input history |
Scroll | Navigate transcript |
? | Show keymap help |
Status and Active Time
The main status row presents the exact main branch label as Main, including Main (dirty) when the working tree is dirty, without renaming the branch or changing any other branch casing. It reserves its right edge for a live cumulative agent-active clock while Dext handles a turn. The clock advances during provider waits, tool calls, permission/auth waits, and in-turn compaction; while Dext is idle awaiting user input, it pauses and is hidden, then resumes on the next turn. It updates through the existing redraw cadence and uses compact forms such as 7s, 7m 05s, and 1h 07m without adding a timer thread.
Todo View
Ctrl+L opens a clean read-only modal during ordinary idle or busy work. Security-critical permission and local-auth prompts intentionally retain input and rendering priority and must be resolved or canceled first. The modal loads persisted session/project todos at startup, refreshes after todo_read/todo_write, scrolls with arrows, Page Up/Down, Home/End, or the mouse wheel, and closes with Ctrl+L, Esc, or q. Empty-state parsing matches Dext's generated sentinel lines exactly, so ordinary todo text cannot clear the modal accidentally. When todo progress is the live-status fallback above the composer, the battery follows the list length up to seven cells: Todos 3/4 ■■■□ maps one cell to each short-list item, while a longer list such as Todos 15/20 ■■■■■□□ stays capped and proportional. Partial progress retains at least one filled and one empty cell, and the active task remains visible when space permits. Editing remains on the existing todo_write path so validation, approval, checkpoint, and session-state behavior are not duplicated. The backend viewer remains the only alternate-screen surface.
Tool Result Rendering
Tool results are rendered as collapsible blocks with density grouping. Long outputs are compressed with head+tail preservation and JSON shape hints. Failed native write_file, edit_file, and multi_edit blocks explicitly state that no edits were applied, matching the atomic prepare-and-replace invariant. The alternate-screen backend viewer normalizes CRLF across arbitrary output chunks without introducing blank rows and visually matches the main TUI with a Dext header, agent-active clock, command summary, styled stdout/stderr lanes, output panel, command position, and compact controls. It continues to use the existing bounded ring buffer, selection, scrolling, event stream, and permission/auth priority.
Markdown Rendering
Assistant text blocks are rendered using tui-markdown with sanitization and terminal-safe formatting rules. Frugal mode applies the stricter pseudo-tool-protocol sanitizer across partial-stream recovery, transcript rendering, and the inspector: serialized or multiline tool-call-like assistant payloads are replaced with [tool call redacted; waiting for structured tool event] while surrounding prose remains visible. Standard mode retains the narrower legacy line detector. Rendering preserves readability under narrow widths and avoids alternate-screen dependence. Thinking and steering blocks use a light or dark contrast palette. DEXT_THEME=light|dark is the explicit override; otherwise Dext converts the terminal's COLORFGBG 16/256-color background index to luminance when present and falls back to dark.
Dependency and resize contract
The exact stack is ratatui 0.30.2, ratatui-core 0.1.2, tui-markdown 0.3.8, crossterm 0.29.0, and unicode-width 0.2.2. The lockfile pins Ratatui's transitive lru cache to patched 0.18.2. Dext selects exact versions and patches exact vendored ratatui-core source to avoid synchronous cursor-position queries during inline replay and extra whole-display clears during horizontal shrink, and to add Terminal::reset_inline_viewport. Every effective transcript-pane width change uses one synchronized terminal update: Dext clears the visible display and resets the inline viewport to the origin without a cursor query, purges stale-width scrollback, and immediately rebuilds the complete logical transcript at the observed width before appending pending output. Clearing before purging removes the still-visible old intro before logical history replays it once. Repeated frames at the same width do not rebuild. There is no quiet-settle debounce, visible-suffix overwrite, or short-history exception. This removes mixed-width history, duplicate copies, and width/height-shrink bookkeeping edge cases; the explicit tradeoffs are complete replay work during resize bursts and replacement of pre-Dext shell scrollback. A prepared insertion batch that fails remains separate from newly queued raw output, so retry does not regroup or rerank it.
The Unix real-PTY regression suite starts each Dext child in a fresh session with the slave PTY as its controlling terminal and applies resize geometry through that slave endpoint, matching real terminal resize delivery on macOS and Linux. Resize assertions wait for the replay marker with a bounded deadline rather than assuming a fixed scheduler delay on shared CI hosts. It verifies editable input during streaming, resize survival with populated history, bounded cursor queries, a visible-display clear before each paired scrollback purge, exactly one Dext intro in every replay segment, terminal-height-bounded complete replay, reconstruction through simultaneous width/height shrink, no repeated rebuild at a stable width, and completed output after resize. Its final stream marker has a bounded 10-second wait so slower macOS CI hosts do not create false negatives. A separate native Windows ConPTY test launches the real binary, submits /status, verifies the default approval/sandbox policy, exits through /quit, and checks clean process termination. The harness forces null std handles so ConPTY children bind pseudoconsole stdio even under redirected test capture, and companion self-check tests validate the pseudoconsole plumbing with cmd.exe and a non-interactive dext --version run. Submitted /quit and /exit mirror into the render loop's quit state, and the keyboard-reader join at shutdown is bounded so a blocked console read cannot stall process exit. Both CI and release workflows require the platform-appropriate harness. See docs/TUI.md and vendor/ratatui-core/DEXT_PATCH.md for the maintained contract and patch rationale.
Safety & Recovery
dext doctor reports ok, info, and warn findings for the effective approval/sandbox policy, provider/auth state, bounded latest session/journal state, and Git recovery metadata without making provider calls. Checkpoint findings name observed unsafe or recoverable modes, distinguish the 256 KiB doctor inspection ceiling from the 16 MiB runtime manifest limit, say when mutating tools are blocked, and point to dext checkpoint repair only for repairable manifest validation failures. Doctor remains inspection-only and exits 0 even when warnings are present.
Git_checkpoints.rs .rs
Git-native recovery checkpoints created before approved non-read-risk tool calls in Git workspaces.
Checkpoint Lifecycle
- Create — Immediately before each sequential tool dispatch, a checkpoint is created under
refs/dext/checkpoints/<session>/<timestamp>-<ordinal>-<tool>-<random-nonce>; a later call in one round therefore captures state produced by earlier calls - Dirty state capture — If the worktree is dirty,
git stash createcaptures a snapshot without touching the working tree or reflog - Untracked sidecars — Direct file tools preserve an untracked target. Write-risk
bash/awk/csvkitcheckpoints inventory up to 500 existing untracked paths, preserve regular files within 8 MiB/file and 32 MiB total bounds, and preserve bounded UTF-8 symlink targets without following them. Non-UTF-8 names, unsupported types, and path/type/size bounds are explicit partial-recovery gaps. Checkpoint storage containers must be real directories; on Unix they must be current-user-owned,.dextmust not be group/world-writable, and managed checkpoint, sidecar, and blob directories are owner-private. Locked Unix mutations may repair modes on current-user-owned managed directories and read-only mode drift on owner-owned manifest/lock files; inspection does not repair them, restore rejects unsafe sidecar/blob containers, and pruning retains unsafe artifact directory trees with bounded warnings while unlinking only an orphan top-level sidecar symlink without following it. Regular-file content is stored in owner-private SHA-256-addressed blobs shared by retained checkpoints; unchanged source paths reuse the session cache only while source and blob metadata fingerprints remain stable, preview/restore rehash blobs before trusting them, and prune or failed checkpoint creation removes valid unreferenced/new blobs. Malformed or unsafe blob entries and sidecar directory trees remain untouched and produce bounded warnings without stopping other retention cleanup; an orphan top-level sidecar symlink with a valid checkpoint ID is unlinked without following it. Owner execute state is descriptor metadata. Manifest rows carry 11 or 12 tab-separated fields; the retired pre-JSON 8/9-field encodings are no longer parsed, so every path in a current manifest is validated by one repo-relative rule with no weaker alternative a row can select. Current 12-field manifests record exact direct-sidecar membership; 11-field manifests without that field fail conservatively before mutation when a missing artifact is ambiguous rather than deleting current path content. A recognized retired row must match the complete retired field grammar and is skipped with a warning so one stale row cannot disable/undoor block write-risk tools. Its recorded OID must match any live checkpoint ref; retention publishes the compacted manifest before deleting expired or integrity-matched retired refs and artifacts, so cleanup failure leaves orphan state instead of a manifest naming a deleted recovery point. Mismatches and other corrupt or tampered rows fail the manifest closed. A recovery gap triggers separate repository/session-scoped approval: denial blocks the command, while approval preserves tracked/staged state and the bounded subset. Other checkpoint failures remain fail-closed. Repositories without an initial commit still block writes that would overwrite existing state. A workspace with no.gitmarker is non-Git unless ambientGIT_DIR/GIT_WORK_TREE/GIT_COMMON_DIRrouting exists; routed-without-marker and malformed-marker cases fail loudly because Dext-owned Git commands scrub routing variables. - Manifest — Appended to owner-private
.dext/checkpoints/manifest.txt;/.dext/is added to the repository-local Git exclude. Rows are tab-separated with 11 or 12 fields; a 12-field row adds the exact direct-sidecar membership index. Untracked preview entries with unsafe host-native targets are omitted, and a malformed field fails its row closed rather than degrading it. Runtime manifest reads are capped at 16 MiB; doctor inspects at most 256 KiB and reports a larger runtime-bounded manifest as uninspected rather than corrupt. Symlinks, hard links, foreign ownership, and group/world-write access remain integrity-fatal with observed modes and actionable errors. Owner-owned manifest/lock files that are only group/world-readable are normalized to0600at startup and the pre-mutation boundary. Checkpoint-freedext checkpoint repairand/undo --repairquarantine invalid manifest bytes asmanifest.txt.quarantine-<timestamp>-<nonce>, recreate an empty private manifest, and retain hidden refs until prune. Retention writes the compacted manifest first, then removes expired/retired refs and orphan artifacts while holding the operation lock; forensic quarantine files survive ordinary prune.
Restore Modes
| Mode | Description |
|---|---|
Preview | Show diff vs current worktree without modifying anything |
Worktree | Restore affected paths from the checkpoint OID with literal Git pathspecs; revalidate and atomically replace captured sidecar files/symlinks on supported platforms |
ResetHead | Hard reset HEAD to checkpoint's original HEAD |
Pruning and Repair
Default pruning keeps the 20 newest checkpoints and removes entries older than 168 hours (7 days). Pruning first publishes the reconciled local manifest, then removes orphaned refs/dext/checkpoints/*, legacy sidecar directories, and valid unreferenced content-addressed blobs for bounded disk growth. Malformed or unsafe blob entries and sidecar directory trees are retained for inspection and reported with bounded warnings without stopping other cleanup; an orphan top-level sidecar symlink with a valid checkpoint ID is unlinked without following it. Quarantined manifests are preserved as forensic evidence. Use dext checkpoint repair, dext undo --repair, or /undo --repair when doctor reports manifest corruption. Never mirror-push refs/dext/*.
Checkpoint Triggers
Always checkpointed: write_file, edit_file, multi_edit, todo_write, git_commit. Other tools are checkpointed when tool_policy::classify_command_risk() returns Write or Danger. Required checkpoint creation is fail-closed before execution; HTTP and other non-filesystem side effects are not recoverable merely because a local Git checkpoint exists.
Mutation_preview.rs .rs
Generates in-memory line-level mutation previews before applying direct file mutations. Shows the preview during permission prompts without touching disk.
Preview Flow
- Read the current file content (or empty for new files)
- Compute the proposed content (apply edit/multi-edit transforms in memory)
- Generate an alignment-aware Myers line diff with one context line around changed hunks; final-newline-only changes are explicit, and inputs above the line budget use a bounded conservative fallback
- Keep added/removed counts for the full proposed change even when rendered output is truncated
- Cap at 4,096 bytes with a truncation notice
- Show added/removed line counts and whether it's a new file
Sandbox Validation
All mutation paths are canonicalized and validated against the effective write scope. Inside a Git worktree that scope is the canonical repository top-level, even when Dext was launched from a subdirectory; command cwd and project context remain the selected sandbox directory. Canonicalization normalizes Windows verbatim-path forms before native Git pathspec, file mutation, checkpoint, and optional workspace-write scope comparisons. /sandbox prints both cwd and write scope and can widen/change them in-session. Paths outside that scope are rejected with the effective root and remedy. Cross-platform display and Git pathspec rendering strips Windows verbatim prefixes and normalizes separators to forward slashes; work-ledger filtering recognizes both native and foreign-platform absolute paths.
Extensibility
Orchestrator.rs — Runtime Intelligence .rs
Per-turn runtime state that guards against loops, manages external resource access, and tracks objectives.
Work Phases
| Phase | Description |
|---|---|
Probe | Initial exploration — reading files, searching, understanding the codebase |
Scale | Expanded collection — triggered when probe passes for external hosts |
Synthesize | Final delivery — writing files, committing, producing the answer |
Guard Systems
- Dedupe cache — Short-circuits identical external requests within a turn
- Similarity guard — Blocks after 3+ similar unproductive bash/file operations
- Tool retry budget — Circuit breaker after 3+ failures with same error signature
- Empty tool call loop detection — Detects provider bug where tool arguments are dropped (threshold: 4 consecutive empty calls)
- Auth circuit breaker — Blocks hosts after 2 auth failures
- Feasibility guard — Requires single-item probes before bulk external collection
Objective Tracker
Parses user prompts to extract checkpoints (plan, analyze, implement, verify, document). Exact verification keywords avoid turning descriptive morphology such as verifiable into new work. Satisfaction is refreshed after every tool round and is derived from tool usage, bash commands, and explicit completion reports such as “checks pass,” so the next model request does not receive a stale [unresolved] checkpoint after custom checks pass.
Adaptive Caps
Tool UI content and result caps scale down dynamically based on context pressure: ≥90% → 25%, ≥75% → 50%, ≥60% → 75% of default. This preserves critical evidence near context limits while reducing prompt bloat.
Packs.rs — Pack System .rs
Packs are shelf-contained, source-first workflows with an optional bounded executable runtime. Dext supplies the create, discover, inspect, maintain, and run lifecycle; users own the content. PACK.md-only packs orchestrate the native tool surface. A reviewed pack may additionally declare runtime.json protocol v1 to expose dynamic tools only while active, without adding pack-specific code to the Dext binary.
Design Contract
PACK.md-only packs add no provider tools; optional reviewed runtimes may add a bounded active-pack tool set.- Source-first reviewability: every pack is plain files in a directory.
- Deterministic discovery and precedence: first resolved name wins after ordered search roots.
- Optional hooks via
phooks.jsonand optional one-shot native runtime viaruntime.json; both remain separate from projecthooks.json.
<shelf>/packs/<name> in a user, project, or explicitly configured shelf root.Pack Object Model (PackInfo)
packs.rs normalizes each discovered pack into PackInfo with:
name,description, declaredcredential_envnames (from front matter or directory defaults)path,pack_md_path, optionalphooks_path, optionalruntime_pathsourcelabel (project/env/user) and shelf ownership
Invocation wraps this as PackInvocation { pack, task } so the task is explicit and auditable.
Discovery and Creation
- Project shelves:
.dext/shelves/*/packs - Explicit shelf roots:
DEXT_SHELVES_DIR - User shelves:
~/.dext/shelves/*/packs
Create reusable packs with dext pack create <shelf>/<name>; add --project only for an explicitly project-local pack. The scaffold creates a minimal PACK.md, refuses overwrite, and is immediately available to normal inspection and explicit invocation. Direct packs/, .dext/packs, ~/.dext/packs, DEXT_PACKS_DIR, and per-pack override roots are not discovery inputs.
Project-local PACK.md content has a repository trust boundary. An explicit /pack or dext pack invocation confirms only that selected project workflow; it does not approve unrelated project shelf metadata. Conversational auto-invocation prompts once per active repository before loading project workflow text. Choosing Always stores a bounded owner-private, single-link project-scoped approval marker on Unix; unsafe or permissive markers are ignored, and /project-extensions reset refuses unsafe marker shapes while removing a safe marker or clearing a session denial. Denied project pack metadata stays out of the model prompt and cannot shadow a same-named user or run-shelf pack. Project-local credential declarations remain ignored.
The resolver deduplicates by canonicalized path and normalized pack name. Name collisions are resolved by precedence order, not random filesystem order.
Pack Layout and Front Matter
my-pack/
├── PACK.md # required; markdown workflow with YAML front matter
├── runtime.json # optional bounded executable protocol v1 manifest
├── phooks.json # optional hook template for this pack
├── bin/ # optional ordinary or runtime helpers
└── README.md # optional human docs
---
name: my-pack
description: One-line workflow summary
credential-env: [SERVICE_TOKEN]
---
# Workflow
1) Setup
2) Probe
3) Transform
4) Verify
5) Deliver
Only PACK.md is required. Front matter stays minimal: identity/description plus an optional inline credential-env list of exact credential-shaped names required by the pack's own helper. That field is honored only for user and DEXT_SHELVES_DIR packs; project-local declarations are ignored.
Prompt Injection Model
pack_prompt() builds a bounded invocation prompt (cap: PACK_PROMPT_CAP = 32_000 bytes) containing:
- pack identity and source metadata
- paths for workflow and optional hooks
- pack-scoped environment names (
DEXT_PACK_DIR,DEXT_PACK_<NAME>_DIR), which the runtime supplies to active-packbashcalls and hook processes - declared credential names only, never their values
- capped
PACK.mdworkflow body - explicit user task text
This gives the model procedural guidance without changing core runtime policy unless the selected pack declares an approved runtime. Workflow loading and optional runtime activation must succeed before pack hooks or environment are activated. Once active, phooks.json entries are added to the hook set, and pack-scoped environment variables are passed to subsequent bash tool commands and hook processes. Declared credential values are narrower: for user and DEXT_SHELVES_DIR packs, they reach only a simple direct invocation of the active pack's own ordinary native bin/ helper, never runtime helpers, hooks, arbitrary bash, pipelines/redirections, prompts, logs, or sessions; provider-auth names remain excluded. Project-local declarations are ignored. Changing the sandbox root clears active pack state.
Compact pack/shelf metadata is byte-bounded and normalized to one safe line before entering the stable prompt. Shelf Context bodies may retain ordinary newlines and tabs, but terminal controls and Unicode line separators are normalized before injection.
Pack Runtime Protocol v1
src/pack_runtime.rs loads runtime.json only as a regular non-symlink file capped at 256 KiB. The manifest declares version 1, a relative regular executable no larger than 256 MiB inside the canonical pack root, optional bounded arguments, a 1–604800-second timeout, a continuation budget, and at most 32 dynamic tools. Tool names must be provider-safe and collision-free across the full native catalog, active dynamic tools, and host approval pseudo-operations. Recursive schemas require an explicit supported type at every node and accept only type, properties, required, boolean additionalProperties, items, enum, and bounded description; schema annotations follow the session's lean/full tool profile on provider wires. Every tool declares read, write, or danger risk, defaulting to write.
Approval always automatically authorizes runtime activation after exact executable identity validation; approval never disables it, while prompt-level Always under prompting profiles is in-memory, nonserialized, and scoped to the exact canonical pack-directory/source identity, manifest digest, and executable digest. Dext displays the executable SHA-256 at approval and rehashes the regular no-follow file before every invocation; changed bytes require reactivation. Changing approval or sandbox policy revokes the active runtime, its dynamic grants/denials, and queued callbacks. Activation, idle events, and every declared tool use the selected sandbox profile consistently. Write/danger tools retain durable side-effect journaling and fail-closed Git checkpoint controls. Runtime helpers are one-shot process-group-contained calls, receive no inherited credentials, and exchange exactly one JSON request/response through stdin/stdout. A present malformed timeout override fails closed. The configured deadline bounds stdin delivery and root execution; output drain after process-tree cleanup has a separate one-second cap. The default is 120 seconds; manifest timeout_seconds configures it and DEXT_PACK_RUNTIME_TIMEOUT_SECS overrides it within the same 1–604800 bound.
Requests identify activate, tool, or idle, plus pack/session/project context, bounded state, turn/iteration/compaction context, and optional tool input. Responses may contain content, an error bit, replacement state, and at most 16 effects: steer, delayed continue (maximum 30 seconds), or a Markdown view. Request/response size is 256 KiB, state 64 KiB, content/effect text and views 128 KiB; the subprocess capture path preserves that full response ceiling. Runtime-exposed content, effect text, view titles/Markdown, and queued prompts reject unsafe terminal controls. State/effects/continuation accounting validates and commits atomically. State, used continuation count, and at most 32 queued prompts totaling 64 KiB persist inside the existing owner-private 256 KiB session-header ceiling; interrupted delayed prompts are canceled and refunded. Every runtime result uses a durable state/result checkpoint, including read-risk calls. Resume preserves current-run approval and sandbox policy and discards saved grants. Before changing the live agent, it preflights project-extension trust, exact saved source plus canonical pack-directory fingerprint, manifest/hash/state accounting, and approval against the current executable digest; changed, missing, shadowed, denied, or malformed runtimes cannot partially apply saved sandbox/model/session state. Content, steering, views, and surfaced activation/idle errors are privacy-redacted. Opaque structured state is bounded and owner-private but is not rewritten by privacy redaction, so helpers must not place secrets in state. Active dynamic tools participate in /allow, /revoke, and /allowed.
The user-owned autoresearch pack exercises this protocol with bounded experiment state, metrics, checks, continuation, and Markdown views. It requires a repository with an initial commit and a real non-symlink .auto directory; measurement, check, and hook programs must be executable regular non-symlink files in their expected locations. Its helper restores persisted segment/cap/continuation/stopped state plus measured-but-unlogged results; stopped or capped segments reject new runs until reinitialized, and reinitialization cannot discard an unlogged result. Each repository using the pack owns its local .auto experiment workspace; the Dext source repository ignores its root .auto/, while reusable pack code belongs in the user's shelf. Append-only .auto/log.jsonl evidence is a bounded regular no-follow, single-link file outside keep commits. Runtime-owned Git calls scrub ambient routing/credentials and suppress hooks, fsmonitor, signing, external diff, and configured filter subprocesses. Only one active autoresearch/Dext session is supported per Git working tree because protocol state is session-bound.
Execution Paths
- CLI:
dext pack create <shelf>/<name>,list,inspect, andrun - Interactive:
/pack create,list,inspect, andrun - Conversational detection:
invoke <name>/run <name> on ...patterns mapped by selector inference
Operational Guidance for Pack Authors
- Write reproducible loops: inputs, stop conditions, verification gates.
- Install reusable packs under user-global Dext scope by default; use project-local roots only for intentionally repo-scoped packs.
- Keep shell helpers idempotent; prefer deterministic outputs for agent reuse.
- Use
phooks.jsononly when needed; packs must still function without hooks. - Treat pack workflows as code: version, test on disposable repos, and review diffs.
Outside the active sandbox, native mutation tools may write only below a concrete user pack directory (~/.dext/shelves/<shelf>/packs/<pack>/...) containing a regular PACK.md. Shelf manifests and loose files directly under packs/ remain outside that exception. Dext revalidates the destination and marker before atomic replacement. Same-user replacement is outside Dext's isolation boundary.
Shelves.rs — Shelf Registry .rs
Shelves are typed metadata registries over packs. They describe capabilities and signal/effect behavior without adding provider-visible tools.
Why Shelves Exist
- Give the model structured capability hints (commands/hooks/context) with low token cost.
- Separate extension metadata from prompt prose.
- Enable scoped override rules across core/user/project/run environments.
Manifest and Type System
shelf.json is parsed into ShelfManifest → PackManifest → Ability enums:
| Type | Purpose |
|---|---|
ShelfManifest | Identity, description, origin/scope, mode, and contained packs |
PackManifest | Pack id/name/version/description with typed abilities |
Ability | Tool, Command, Hook, Context |
Grant | Read/Write/Network/Process/Secret/Browser permission intent metadata |
Exposure | Hidden / OnDemand / Visible model-facing exposure level |
Signal and Effect Types
The shelf module defines a typed signal/effect vocabulary for in-process shelf implementations. Filesystem shelf.json manifests must be regular non-symlink files no larger than 1 MiB and are declarative metadata: a matching load/prompt hook declaration can opt declared context into bounded prompt injection, but manifests do not register executable tools or slash commands and do not supply arbitrary effect handlers.
| Signals | Typical Use |
|---|---|
load, prompt, tool(before|after), turn(start|end), compact, shutdown | Typed lifecycle vocabulary for in-process shelves |
| Effects | Behavior |
|---|---|
note | Diagnostic annotation |
context | Inject prioritized context text |
block | Hard-stop signal flow with explicit reason |
rewrite_tool | Typed input-rewrite effect for an in-process shelf; not executed from a static manifest |
state | Typed state effect for an in-process shelf; static manifests do not persist it |
Block effects terminate in-process signal flow early. Static manifest shelves only produce context/note data for opted-in load or prompt signals. Under approval always, project shelf metadata proceeds automatically; prompting profiles request first-use confirmation per active repository, and choosing Always persists a bounded owner-private, single-link project-scoped decision marker on Unix. Unsafe or permissive markers are ignored, and /project-extensions reset refuses unsafe marker shapes while removing a safe marker or clearing a session denial. Before approval under a prompting profile, project metadata is omitted from the model prompt, cannot shadow same-key trusted user/run metadata, and cannot contribute behavioral tool effects, while approved project context is explicitly labeled repository-controlled.
Discovery and Scope Precedence
| Scope | Rank | Location | Intent |
|---|---|---|---|
Core | 0 | In-process registration | Base defaults; release binaries do not probe build-machine source paths |
User | 1 | ~/.dext/shelves | User-level customization |
Project | 2 | .dext/shelves | Repo-specific policy/context |
Run | 3 | DEXT_SHELVES_DIR | Per-invocation highest-priority overrides |
resolve() keeps one winning ability per key using tuple ordering by scope rank and stable discovery order. This gives deterministic override semantics.
Prompt and CLI Surfaces
render_registry_listing()powersdext shelves//shelvesoperator visibility.registry_summary_for_prompt()injects compact typed ability summaries into model context.- Ability metadata is provider-neutral and does not modify the external tool schema.
Methodology for Building Shelf Ecosystems
- Start with pure packs; add shelf metadata only for reusable capability contracts.
- Define ability keys as stable API-like surfaces.
- Use project scope for repository policy, user scope for personal defaults, run scope for experiments.
- Treat
shelf.jsonas versioned interface documentation and test precedence resolution.
Testing & Performance
Testing
Unit Tests (main_tests.rs)
The test suite covers provider catalogs and request shaping, auth and state formats, stream/tool-call assembly, tool policy, sandboxing, side-effect journals, recovery checkpoints, TUI rendering, and runtime orchestration. Unit tests are hermetic against user state: when a test does not set DEXT_HOME, the state directory resolves to one throwaway per-process home under the OS temp root, so live test agents cannot leak project/session residue into the real ~/.dext. Git fixture subprocesses explicitly clear ambient repository-routing variables such as GIT_DIR and GIT_WORK_TREE, so parallel environment-isolation tests cannot redirect unrelated temporary repositories. Pricing override coverage uses pure default/override composition rather than mutating process-global pricing variables, so parallel local-provider and cloud-pricing tests cannot observe transient test values.
- Provider catalog loading, normalization, and model resolution
- Auth store operations (save, load, normalize)
- Session header parsing and backwards compatibility
- Tool input validation and risk classification
- Bash guardrails and sudo detection
- Checkpoint creation and restore logic
- Objective tracking and satisfaction assessment
- URL parsing/error redaction, proxy isolation, shared bounded DNS reuse/lookups, destination policy, dangerous/duplicate header rejection, exact decoded-body caps, bodyless response semantics, safe cross-origin GET/HEAD redirects, sensitive redirect replay blocking, and automatic-
Referersuppression; redirect fixtures use bounded blocking reads on accepted sockets for consistent Windows behavior
Run with: cargo test --release --locked
Real-PTY TUI Regression Suite (tests/tui_smoke.rs)
Spawns the real Dext binary in a Unix PTY at narrow and wide terminal sizes and verifies:
- Application launch, banner/composer rendering, help, multiline input, and clean Ctrl+D exit
- Editable input while output streams and process survival during populated-history resize bursts
- One visible-display clear before one scrollback purge per effective populated-transcript width change, exactly one Dext intro per replay segment, resize-bounded cursor queries, and terminal-height-bounded complete replay chunks
- Completed stream output and accepted input after resize, with no crash markers
Run with: cargo test --release --locked --test tui_smoke -- --nocapture
The complete verification gate also runs formatting, Clippy with warnings denied across the Linux, macOS, and Windows CI matrix, vulnerability auditing, dependency-license policy checks, the vendored ratatui-core unit tests, a locked release build, Unix PTY smoke tests, and the native Windows ConPTY smoke test. Windows CI and release builders parse and execute the full installer harness under both inbox Windows PowerShell 5.1 and PowerShell 7; each engine evaluates the installer from in-memory text through Invoke-Expression, matching the public irm | iex path. Platform-specific fixtures follow host filesystem semantics: the invalid-UTF-8 checkpoint filename case runs only on Unix filesystems that permit creating it, because macOS APFS rejects that filename before Dext can inspect it. Release publication accepts only an annotated tag whose commit is contained in origin/main and whose exact vX.Y.Z value matches Cargo.toml. It generates dext.cdx.json, includes it in SHA256SUMS, and attests and verifies it alongside the four platform archives. The first successful tag run and its end-to-end evidence are recorded in docs/RELEASING.md. On Windows, the scheduler-sensitive fast_bash_command_returns_without_100ms_poll_tail regression runs alone after the remaining release tests. A dedicated child helper flushes a wall-clock timestamp immediately before exiting; the parent measures from that marker until Dext returns and accepts the fastest of three post-exit samples under the original <90 ms bound. This excludes shell startup from the measurement while still detecting a structural 100 ms polling tail, and isolation prevents unrelated suite load from obscuring the process-wait regression. The stdin-backpressure regression still requires bounded completion under the shared deadline, but accepts either the stdin-write or root-process timeout phase on Windows because pipe buffering can complete the write at the deadline boundary; Unix continues to require the stdin-write phase. The tool-call mock provider consumes its bounded Content-Length request body before responding so Windows does not reset the connection with unread request data. See docs/TUI.md for renderer-specific live-terminal checks.
GitHub Pages
The public site at siliconstate.github.io/Dext is deployed from the static docs/ tree by .github/workflows/pages.yml. The workflow validates local links and anchors, uploads an immutable Pages artifact, and gives the pinned deployment action a bounded 15-minute status-poll deadline within a 20-minute job ceiling. Only the deployment job receives pages: write and id-token: write. Third-party actions are pinned to full commit hashes and checkout credentials are not persisted.
main strictly requires Ubuntu, macOS, and Windows CI; active v* rules prevent tag updates and deletion; releases are immutable; and private vulnerability reporting, vulnerability alerts, and Dependabot security updates are enabled. Initial release-tag creation remains a trusted maintainer action guarded by annotated-tag, origin/main-ancestry, and package-version workflow validation; this residual boundary remains tracked in R-008.workspace-write or read-only, shared-temp, PTY, and Cargo-home writes may be denied. The default danger-full-access profile adds no such Dext restrictions, while any parent container, VM, namespace, seccomp, Seatbelt, service-account, or host policy remains authoritative.Benchmarks (benches/dext_bench.rs)
Criterion benchmarks for performance-critical paths:
| Benchmark | What it measures |
|---|---|
production_sse_decode/coalesced_provider_read | Production SSE framing for 512 events delivered in one provider read |
production_sse_decode/fragmented_97_byte_reads | The same production decoder under fragmented network reads |
Run with cargo bench; CI and the release quality job compile the benchmark with cargo bench --no-run --locked.
Build Profile
Release builds use: lto = false, codegen-units = 16, strip = "symbols" — optimized for build speed while keeping binary size small.
Reference
CLI Reference
| Command | Description |
|---|---|
dext | Start interactive session |
dext "prompt" | One-shot task |
dext -p | Read prompt from stdin |
dext --resume | Resume latest session |
dext --seat <name> | Start a new session with a durable project identity |
dext --seat <name> --resume | Resume that Seat's latest durable session |
dext seat list|show <name> | Inspect project Seat records |
dext seat set <name> ... | Set or clear a bounded Seat label/summary |
dext --fork | Fork latest session into new session |
dext session ... | Brief/export/analyze/grep/failures/verification/decision/prune operations |
dext doctor [...] | Inspect effective safety policy and bounded local state without repair or provider calls |
dext pack list|inspect|run ... | Discover or invoke source-first packs |
dext shelves | List typed shelf manifests and ability metadata |
dext --cd <dir> | Change command cwd/project context; in Git repositories, mutation/Git/checkpoint write scope is the containing top-level |
dext --no-session | Don't save session |
dext --pack <name> "task" | Invoke a pack in one-shot mode |
dext --frugal | Select the reduced-context mode |
dext --context-mode standard|frugal | Choose context/cap mode |
dext --toolset default|full | Choose provider-visible tool count profile |
dext --tool-profile lean|full | Choose provider tool schema verbosity |
dext --preview off|simple|git | Choose mutation preview mode |
dext --sandbox read-only|workspace-write|danger-full-access | Set sandbox profile |
dext --eval [NAME] [--sandbox PROFILE] | Run eval harness under the resolved sandbox profile |
dext --output json|stream-json | Machine-readable output |
dext --effort off|minimal|low|medium|high|xhigh|max | Model reasoning effort; supported levels are clamped per model |
dext --reasoning-mode standard|pro | Select GPT-5.6 execution mode; sent only by official OpenAI Responses requests |
dext --approval ask|auto-read|auto-write|never|always | Approval profile |
dext --trust | Explicitly select approval always |
dext --no-trust | Explicitly select the ask approval profile |
dext --budget <amount> | Session budget cap: dollars, tokens, or one of each (e.g., $0.50, 100ktok, $0.50 + 100kt); duplicate dimensions are rejected |
Auth Subcommands
| Command | Description |
|---|---|
dext auth providers | List available providers |
dext auth login <provider> [credential|web|import] | Open a provider login flow; omit command-line credentials for interactive use |
dext auth logout <provider> | Remove stored credentials |
dext auth status | Show auth status for all providers |
Other Subcommands
| Command | Description |
|---|---|
dext undo --list | List recovery checkpoints |
dext undo --preview <id> | Preview checkpoint restore without modifying files |
dext undo --apply <id> | Apply a checkpoint restore |
dext checkpoint repair | Quarantine an invalid checkpoint manifest byte-for-byte and recreate an empty private manifest |
dext undo --repair | Alias for checkpoint manifest repair |
dext undo --prune | Remove expired and excess checkpoints plus orphan refs/artifacts |
dext pack list | List available packs |
dext pack inspect <name> | Show pack details |
dext pack run <name> "task" | Run a pack |
dext shelves | List shelf manifests and abilities |
Slash Commands
Slash completion lists each /login provider exactly once by its provider id; numbered selector aliases remain accepted but are not shown as duplicate login choices. Planning is conversational rather than a separate mode: ask Dext to inspect and propose a plan without editing, revise it in the same thread, then tell it to proceed. The retired /plan command is no longer intercepted, so equivalent text is handled as an ordinary prompt. When a prompt reads as planning/analysis-only (for example “plan …”, “review …”, “don’t change anything”), Dext injects an advisory-only turn policy into the volatile runtime status directing read-only tools and a structured Goal/Findings/Steps/Risks answer; a bare approval such as “go” or “proceed with the plan” injects an implementation policy directing the agreed plan into todos before editing. Explicit mutation requests always win over scoping clauses, question-phrased prompts (ending in ?) are never treated as approvals, and mid-turn queued user updates re-evaluate the policy so a steering approval or hold-off takes effect immediately. The policy note steers rather than blocks — approval prompts and /sandbox-profile read-only remain the deterministic enforcement layers for untrusted or weaker models.
Structured listings from /help, /tools, /system, packs, shelves, and sessions retain the established /sessions hierarchy: compact count headers, bold section labels, two-space names, four-space details, and detached Use: footers. Dense name/description catalogs such as /help use aligned rows at 64 columns and wider, with hanging description wraps, and fall back to stacked rows on narrow panes. The TUI passes its actual transcript-pane width into slash rendering; output keeps a two-cell gutter and a 120-column readability cap. /system preserves prompt paragraphs, blank lines, and leading indentation while wrapping prose rather than hard-splitting every display-width chunk. Dynamic fields have terminal escapes, controls, line separators, and bidi formatting controls removed before layout. Every physical row is bounded by Unicode display cells; only a grapheme that cannot fit in an otherwise impossible one-cell measure is replaced with ?. An explicit structured-slash event keeps listings free of dim bullet prefixes when ANSI color is disabled; generic confirmations such as /model and thinking-effort status retain the faded info treatment.
| Command | Description |
|---|---|
/help | Show available commands as a grouped listing in the established /sessions presentation |
/quit, /exit | Exit Dext |
/reset | Clear conversation history |
/tools [default|full] | List (profile, exposed, permission-gated, explicit session grants, hidden sections) or switch provider-visible tools |
/history | Show turn count and last 5 messages |
/system [text] | Show the composed system prompt with its source files, or replace the base prompt |
/allow <tool> | Auto-approve a native or active runtime tool for this session |
/revoke <tool> | Remove auto-approval for a tool |
/allowed | List native and active-runtime grants |
/trust [on|off|status] | Auto-approve all gated tools |
/approval [profile] | Set approval profile |
/preview [off|simple|git] | Set mutation preview mode |
/sandbox [path] | Show cwd plus effective write scope, or change the sandbox root in-session |
/sandbox-profile [profile] | Set sandbox: read-only, workspace-write, danger-full-access |
/privacy [on|strict|off|status] | Control local redaction and optional strict native-read path/search-scope blocking |
/effort [level] | Set thinking effort: off, minimal, low, medium, high, xhigh, max |
/reasoning-mode [standard|pro|next|prev|status] | Select or inspect GPT-5.6 execution mode; reports inactive outside official OpenAI Responses |
/model [name] | Show or change model |
/provider [id] | Show or change provider |
/models | List available models |
/providers | List providers and auth status |
/login <provider> [credential|web|import] | Login to a provider; pending API keys/tokens and manual OAuth callbacks can be pasted directly in Dext |
/logout <provider> | Logout from a provider |
/compact [N%] | Run compaction or set threshold. After compaction the generated summary is rendered once into TUI/CLI history for every provider; the summary model’s own stream stays muted so responses-contract providers no longer leak it as live assistant output while others showed nothing |
/context [mode] | Set context mode: standard, frugal |
/tool-profile [lean|full] | Set provider tool schema verbosity |
/usage | Show cumulative token usage |
/status | Show runtime diagnostics |
/tokens | Approximate tokens per message and top context hogs |
/diagnostics | Run rust-analyzer diagnostics, falling back to cargo check |
/save <name> | Save history/config to named JSONL session |
/export [html|jsonl] [path] | Export the current session |
/resume [name] | Resume latest or named session |
/sessions ... | List session history in the established session presentation, or analyze/brief/grep/failures/verification/decisions |
/budget [cap] | Set/show a dollar, token, or combined cap; off clears it |
/pack create|list|inspect|run | Create or use shelf-contained packs |
/shelves | Show shelf registry |
/project-extensions [status|reset] | Inspect or reset repository-scoped project extension approval |
/undo [--list|--apply|--repair|<id>] | Recovery checkpoint preview/apply/repair management |
Tool Reference
Dext implements 18 built-in provider-visible tools. The default profile contains 13 core tool names. Specialized built-ins (jq, fzf, awk, git_log, csvkit) require dext --toolset full, DEXT_TOOLSET=full, or /tools full. Ordinary workflow packs orchestrate this surface; a separately approved runtime.json pack may add bounded dynamic tools for the active session.
File Operations
| Tool | Permission | Description |
|---|---|---|
read_file | Read | Read file with line numbers. Positive offset/limit windows get a larger cap, stop once additional data is detected, and can be cancelled between bounded chunks. |
read_symbol | Read | Locate a source symbol or block around a line number. Selector ranges are validated; loading is cancellable and capped at 8 MiB. |
write_file | Write | Write content to file, creating parent dirs. Overwrites existing. |
edit_file | Write | Replace exactly one occurrence of old_string with new_string. |
multi_edit | Write | Batch of exact-string edits applied atomically to one file. |
Search & Discovery
| Tool | Permission | Description |
|---|---|---|
fd | Read | Find files by regex pattern. Subprocess-execution flags are rejected. |
rg | Read | Search file contents. Preprocessor and subprocess-capable flags are rejected. |
fzf | Read, full toolset | Non-interactive fuzzy filter. |
Shell & Process
| Tool | Permission | Description |
|---|---|---|
bash | Varies | Execute shell command with pipefail. Risk classified. |
awk | Varies, full toolset | AWK text processor. Optional stdin. |
Data Processing
| Tool | Permission | Description |
|---|---|---|
jq | Read, full toolset | Query/transform JSON. |
csvkit | Varies, full toolset | CSV processing suite: csvcut, csvstat, csvgrep, csvjson, etc. |
HTTP
| Tool | Permission | Description |
|---|---|---|
http | Varies | HTTPie-style client with HTTP/2 and gzip/Brotli decoding; provider, OAuth, and local-context clients retain HTTP/1/no-auto-decompression behavior. The entire DNS answer is validated before one shared 256-entry cache retains at most 32 addresses per host; connect, lookup, idle-read, 10-minute total-request, redirect, and exact decoded-response bounds apply. --extract-text reads at most 128 KB of source. Duplicate/framing/method-override headers and URL credentials are rejected; errors omit URLs; automatic Referer and HTTPS downgrades are disabled. Headerless/bodyless GET and HEAD requests may follow validated cross-origin redirects, while sensitive requests remain same-origin. GET, HEAD, and OPTIONS requests with raw bodies are Danger-class. IPv4 current-network/broadcast, IP multicast, and IPv6 unspecified destinations are always blocked. Loopback, private/CGNAT, unique-local, link-local, and metadata destinations are blocked unless narrowly opted in. |
Git Operations
| Tool | Permission | Description |
|---|---|---|
git_diff | Read | Show git diff. Prefer stat=true first. |
git_log | Read, full toolset | Show recent git log entries. |
git_commit | Write | Stage files and create commit. |
Task Management
| Tool | Permission | Description |
|---|---|---|
todo_read | Read | Read project todo list. |
todo_write | Write | Replace project todo list. |
Environment Variables
| Variable | Default | Description |
|---|---|---|
DEXT_HOME | ~/.dext | Dext state directory |
DEXT_SESSIONS_DIR | Project-scoped | Override sessions directory |
DEXT_LOGS_DIR | Project-scoped | Override logs directory |
DEXT_LOG_ARCHIVES | 0 | Number of log archives to keep (max 16) |
DEXT_PROVIDER | Catalog active | Active provider ID |
DEXT_PROFILE | Catalog active | Alias for DEXT_PROVIDER |
DEXT_API_PROVIDER | Catalog active | Provider selection by API family |
DEXT_API_KEY | — | Override API key for any provider |
DEXT_MODEL | Profile default | Override model for any provider |
DEXT_MODEL_FORCE | false | Force DEXT_MODEL even if incompatible |
DEXT_PROVIDER_CONNECT_TIMEOUT_SECS | 15 | Provider TCP/TLS connection deadline |
DEXT_PROVIDER_FIRST_BYTE_TIMEOUT_SECS | 180 cloud · 600 local | Deadline through response headers; one positive override applies to all providers |
DEXT_PROVIDER_STREAM_IDLE_TIMEOUT_SECS | 90 cloud · 300 local | Maximum idle interval between provider body/stream chunks |
DEXT_MODEL_{PROVIDER} | — | Provider-specific model override |
DEXT_BASE_URL | Profile default | Override base URL for any provider |
ANTHROPIC_BASE_URL | Profile default | Override Anthropic-family base URL |
CLAUDE_CONFIG_DIR | User home | Optional Claude state directory used only to read validated installation/account identity from .claude.json in memory for official Anthropic subscription requests |
OPENAI_BASE_URL | Profile default | Override OpenAI-family base URL |
DEXT_CONTEXT_MODE | standard | Context mode: standard, frugal |
DEXT_THINKING_EFFORT | medium | Model reasoning effort: off, minimal, low, medium, high, xhigh, max |
DEXT_REASONING_MODE | standard | Selected GPT-5.6 execution mode: standard or pro; sent only by the capability-scoped official OpenAI Responses route |
DEXT_COMPACT_MODEL | Active model | Optional same-provider summary model; normalized through the provider and used for summary request contract, reasoning capability, mode, and usage pricing |
DEXT_MAX_OUTPUT_TOKENS | Model/default cap | Positive streaming output-token override; ChatGPT/Codex deliberately omits the unsupported field |
DEXT_TOOLSET | default | Provider-visible tool count profile: default, full |
DEXT_TOOL_PROFILE | lean | Tool schema profile: full, lean |
DEXT_MUTATION_PREVIEW | simple | Mutation preview mode: off, simple, git |
DEXT_APPROVAL | always | Approval profile: ask, auto-read, auto-write, never, always. Invalid values warn and use ask unless a valid CLI choice or true DEXT_TRUST takes precedence. |
DEXT_SANDBOX_PROFILE | danger-full-access | Sandbox profile: read-only, workspace-write, danger-full-access. Invalid values fail normal startup unless a valid CLI sandbox override takes precedence. Full access adds no Dext confinement and preserves ambient temp/cache configuration inside the current environment. Optional confined profiles use native Linux/macOS controls when available and otherwise warn and continue with path guards. |
DEXT_PRIVACY | true | Before model context and session logging, replace private-key blocks, real secret assignments, and explicitly labeled SSNs, payment-card numbers, and account identifiers while keeping user-readable files readable. Set to strict to also block sensitive-looking native paths plus hidden, ignored, symlink-following, and sensitive-glob search scopes, including compact/combined ripgrep forms such as -g.env and -ig .env plus wildcard-prefixed sensitive globs such as *.env; disable only for intentionally raw output. |
DEXT_INHERIT_TOOL_CREDENTIALS | false | High-trust opt-in to pass credential-shaped parent environment variables to model-invoked bash/external tools. Hooks and Dext-owned subprocesses remain scrubbed. |
DEXT_BUDGET_CAP | — | Session cap in dollars, tokens (t/tok/token(s)), or one of each separated by +/,; duplicate, empty, or otherwise invalid components fail startup instead of disabling the guard |
DEXT_CONTEXT_WINDOW_TOKENS | Profile default | Override context window size |
DEXT_CONTEXT_WINDOW | Profile default | Alias override for context window size |
DEXT_BASH_TIMEOUT_SECS | 60 | Default bash command timeout |
DEXT_BASH_PATH | bash | Explicit Bash executable. On Windows, the default resolver skips Windows/WSL app aliases and selects a real bash.exe from PATH. |
DEXT_ALLOW_BREAK_SYSTEM_PACKAGES | false | Allow the otherwise-blocked pip --break-system-packages flag |
DEXT_EXTERNAL_TIMEOUT_SECS | 60 | Default timeout for external tools |
DEXT_HOOK_TIMEOUT_SECS | 60 | Default timeout for hook commands |
DEXT_TRUST | false | Explicit alias for approval always when true; false values leave the default always unchanged. |
DEXT_HTTP_ALLOW_LOOPBACK | false | Built-in HTTP tool only: allow loopback destinations. Unspecified/current-network, multicast, and broadcast destinations remain blocked. |
DEXT_HTTP_ALLOW_PRIVATE | false | Built-in HTTP tool only: allow private, CGNAT, and IPv6 unique-local destinations. |
DEXT_HTTP_ALLOW_LINK_LOCAL | false | Built-in HTTP tool only: allow link-local and cloud-metadata destinations. |
DEXT_NO_TUI | false | Disable inline TUI even when a terminal is available |
DEXT_THEME | auto | TUI contrast palette: light or dark; auto converts a COLORFGBG 16/256-color background index to luminance and otherwise uses dark. |
DEXT_SYSTEM | Built-in prompt | Override the base system prompt |
DEXT_SANDBOX | . | Override sandbox root path |
DEXT_HOOKS_FILE | hooks.json | Override project hook configuration file |
DEXT_SUDO_ASKPASS | — | Custom askpass helper for sudo |
DEXT_SHELVES_DIR | — | Additional shelf directories |
DEXT_SESSION_TAG | PID | Session tag for checkpoint ref names |
ANTHROPIC_API_KEY | — | Anthropic API key |
OPENAI_API_KEY | — | OpenAI API key |
KIMI_API_KEY | — | Kimi Code plan API key; distinct from MOONSHOT_API_KEY |
ZAI_API_KEY | — | ZAI GLM API key |
CHATGPT_ACCESS_TOKEN | — | ChatGPT/Codex access token override |
DEEPSEEK_API_KEY | — | DeepSeek API key |
Provider Details
GLM (ZAI)
- Default built-in provider. Uses the Anthropic-compatible API at
api.z.ai/api/anthropic - Catalog models: glm-5.3-flash, glm-5.3-flash[1m], glm-5.2[1m] (default), glm-5.2, glm-5.1, glm-5.0, and glm-4.6. Both Flash spellings declare a 1M-token context, 131,072-token output, model-specific image-input capability, stable list pricing ($0.15 input, $0.03 cached input, $0.50 output per MTok; cache storage is currently free), and native
low/high/maxeffort. Flash always sends enabled thinking: Dext Off/Minimal/Low map tolow, Medium/High tohigh, and XHigh/Max tomax; compaction summaries use enabled low-effort thinking because Flash rejects thinking-disabled requests. The 5.2 variants also declare 1M context; the provider fallback is 200K. Image-input metadata describes the provider model capability; Dext's current persisted conversation blocks remain text/tool based. - Auth: API key via
ZAI_API_KEYordext auth login glm, then paste at Dext's prompt
ChatGPT / Codex
- Uses the OpenAI OAuth flow with a local callback server on port 1455
- Catalog models include GPT-5.6 Sol/Terra/Luna, gpt-5.4 and 5.4-mini, gpt-5.5, Codex variants, gpt-5/mini, gpt-4.1, gpt-4o/mini, o3/o3-mini, and o4-mini.
- GPT-5.6 variants declare 1.05M context and 128K output metadata. This OAuth backend accepts reasoning effort through
xhigh; Dextmaxmaps toxhigh, and selected Standard/Pro mode is not sent. Auth:dext auth login chatgptorCHATGPT_ACCESS_TOKEN.
OpenAI API
- Standard OpenAI Platform API using API-key auth. The built-in official endpoint routes GPT-5.6 through
/v1/responses; other models retain Chat Completions. - Catalog models include the official
gpt-5.6Sol id plus Sol/Terra/Luna variants, gpt-5/mini, gpt-4.1/mini, gpt-4o/mini, o3/o3-mini, and o4-mini. GPT-5.6 exposes nativeminimalthroughmaxeffort plus independent Standard/Pro mode; model-specific metadata overrides the 400K provider fallback. - Auth: API key via
OPENAI_API_KEYordext auth login openai, then paste at Dext's prompt
Anthropic
- The catalog includes current Sonnet, Opus, Fable, and Haiku model variants. Adaptive-capable public models (Sonnet 4.6, Sonnet 5, Opus 4.6/4.7/4.8, Opus 5, and Fable 5) send adaptive thinking plus the selected output effort without a
thinking.displaymember, allowing Anthropic to return thinking deltas instead of requesting an omitted display.xhigheffort maps natively on Sonnet 5, Opus 4.7/4.8, Opus 5, and Fable 5;maxadditionally covers Sonnet 4.6 and Opus 4.6; unsupported extended levels downgrade tohigh. Built-in pricing follows the published per-model rates (Sonnet 5 $2/$10, Opus 4.5–4.8 and Opus 5 $5/$25, Fable 5 $10/$50, Opus 4.1-and-earlier $15/$75 per MTok input/output), which Anthropic applies at standard per-token rates across the full context window. The TUI presents thinking only while verbose display is enabled;stream-jsonemits thinking events, while console text and final JSON omit thinking content. - Context fallback: 200K tokens; Sonnet 5, Opus 5, and Fable 5 declare 1M-token windows.
dext auth login anthropicor/login anthropicstarts the unofficial Claude Pro/Max subscription OAuth flow; re-run withwebto replace an existing OAuth credential.ANTHROPIC_API_KEYremains the standard Anthropic Console API-key path. - Subscription OAuth uses Dext-native request construction with a Claude Code 2.1.224-compatible billing/version fingerprint, seeded XXH64 body checksum, Agent SDK system block, OAuth beta/header set, and per-session/per-request UUIDs. Optional identity metadata is read in memory from
${CLAUDE_CONFIG_DIR:-$HOME}/.claude.jsononly after bounded regular non-symlink validation; identifiers are not copied, printed, or persisted by Dext. - This compatibility path is unofficial, may be restricted by provider terms, and is version-specific. It fails closed during request construction and is isolated from API keys, non-official endpoints, GLM, Kimi, and custom Anthropic-compatible profiles.
Kimi Code
- Uses Anthropic Messages semantics at
api.kimi.com/coding; default model K3 declares 1,048,576-token context, 131,072-token output metadata, and adaptivemaxthinking. - Auth: Kimi Code plan API key via
KIMI_API_KEYordext auth login kimi, then paste at Dext's prompt. This key is distinct fromMOONSHOT_API_KEY.
DeepSeek
- OpenAI-compatible API
- Models: deepseek-chat, deepseek-reasoner — Context: 128K tokens — Auth:
DEEPSEEK_API_KEY
Local (llama.cpp)
- OpenAI-compatible local server at
127.0.0.1:8080— No API key required — accepts the configured server model alias; the built-inQwen3.8shorthand selectsqwen3.8-27b-ud-q5_k_xlwhile requests retain that exact server id. Local providers default to frugal context and probe llama.cpp for the live runtime context window without model-specific built-in context values. If the local server is offline, discovery falls back cleanly and the later provider request reports the ordinary connection error. - For reasoning-capable local profiles, Dext consumes streamed
choices[].delta.reasoning_contentas raw local thinking up to a 4 MiB aggregate stream bound, persists it as thinking blocks, replays only current-turn reasoning across llama.cpp tool-result rounds, and includes that active replay in context-pressure compaction while excluding prior-turn thinking. Local behavior requires the built-inlocalidentity or a parsed URL host oflocalhostor a loopback IP; path/query substrings do not classify a cloud endpoint as local. Verbose TUI andstream-jsonexpose it; console text and final JSON omit it. Local requests explicitly setchat_template_kwargs.enable_thinking: Off sendsfalse, every other effort sendstrue, and declaredreasoning_effortlevels remain in use. These fields and parsing are local-only; cloud Chat Completions behavior is unchanged. Current llama.cpp servers should use--reasoning-preservewhen their template supports reasoning replay.
Configuration Files
Provider catalogs and auth stores are read through bounded non-symlink regular-file checks. On Unix, foreign ownership is rejected; group/world-writable provider catalogs are rejected; owner-owned auth files with loose mode are repaired to 0600 before parsing. dext doctor uses bounded, no-follow, inode-stable inspection and reports the same ownership/mode policy without repairing files.
providers.json (~/.dext/providers.json)
Provider catalog with merged built-in + custom profiles. Editable via /provider and /model commands. Auto-normalized on load. The built-in local profile accepts Qwen3.8 as a case-insensitive alias for qwen3.8-27b-ud-q5_k_xl; both /model Qwen3.8 and /model local/Qwen3.8 resolve from a clean catalog while requests retain the exact server id.
Catalog v2 profiles may set request_contract to anthropic-messages, openai-chat-completions, openai-responses, or chatgpt-responses. Optional model_aliases, model_defaults, and model_specs provide canonical model ids, limits, effort levels, reasoning modes, capabilities, and pricing. Explicit per-model metadata wins; a selected effort uses an exact advertised level when available and otherwise clamps to the nearest supported level. Responses main turns and summaries both use this resolved effort metadata; Off sends none only when advertised, otherwise the reasoning object is omitted. Chat Completions main turns resolve reasoning_effort the same way: declared per-model effort levels win before the legacy model-name clamp, so servers that reject unadvertised levels (for example llama.cpp templates accepting only xhigh/medium/low) receive an advertised value. Context hints in model names such as -128k and [1m] win over provider-wide context defaults. Built-in metadata only fills omissions, and v1 profile fields remain accepted. The built-in official OpenAI profile selects openai-responses automatically only for GPT-5.6 at api.openai.com; custom profiles may select it explicitly without inheriting GPT-5.6-only Standard/Pro behavior. DEXT_PROMPT_CACHE=on|off overrides catalog prompt-cache capabilities for Anthropic-style requests; auto mode uses catalog metadata.
auth.json (~/.dext/auth.json)
API-key entries may reference a parent environment variable by name or intentionally run a !command through bash -lc. Treat write access to this store as code-execution authority.
Stored credentials per provider. Set to mode 0600 on Unix. Supports API-key and OAuth credential types, and retains the type through request construction so Anthropic subscription tokens cannot be confused with Console API keys. Credential-shaped parent environment variables are removed from agent-run subprocesses by default. DEXT_INHERIT_TOOL_CREDENTIALS=1 opts in only trusted model-invoked bash/external tools; hooks and Dext-owned subprocesses remain scrubbed.
.env (~/.dext/.env or $DEXT_HOME/.env)
Optional user-owned Dext settings. Project .env files and parent directories are never auto-loaded, so repository content cannot silently alter runtime policy.
DEXT.md (sandbox ancestry)
Tracked machine-facing project guidance auto-injected into the system prompt. Dext scans the sandbox root and ancestors, labels it as project-controlled guidance, and does not modify the file automatically.
recall.md (optional sandbox ancestry)
Git-ignored agent working memory, auto-injected into the system prompt when present. Whether the agent maintains it is project policy carried by DEXT.md, not an unconditional built-in action. Native write_file, edit_file, and multi_edit mutations whose target filename is recall.md (ASCII case-insensitive) are rejected when the resulting file would exceed 4 KiB; injected recall payloads also share one aggregate 4 KiB budget across sandbox ancestry, so external or shell-written files cannot bypass the context bound. Under the active privacy mode (enabled by default), those native mutation payloads are privacy-redacted before preview, approval, journaling, assistant-history persistence, and disk write, so reviewed, durable, and later model-visible forms agree and secret-shaped content the model saw cannot persist through a native recall mutation. Recall content is redacted again before prompt injection to cover external writers; /privacy off disables these scrubs along with all other redaction. Raw source-file hashes remain provenance evidence. Writes retain normal approval, sandbox, mutation-preview, and checkpoint controls.
hooks.json (project root or DEXT_HOOKS_FILE)
Project-root hooks configuration loaded from hooks.json by default, or from DEXT_HOOKS_FILE when set. This is not the same as pack phooks.json. Hook execution still requires its own approval. Approved pre_tool and post_tool hooks receive privacy-redacted DEXT_TOOL_INPUT; approved post_tool hooks also receive privacy-redacted DEXT_TOOL_RESULT, not raw input or output.