@miller-tech/uap 1.46.4 → 1.46.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/INDEX.md CHANGED
@@ -18,8 +18,8 @@ New here? Start with the [project README](../README.md), then [Getting Started](
18
18
 
19
19
  | Doc | What it covers |
20
20
  |---|---|
21
- | [**What UAP Does Automatically**](guides/AUTOMATIC.md) | Every feature in benefit / when-it-kicks-in terms — install once, it all self-applies ⭐ |
22
- | [**`uap deliver`**](guides/DELIVER.md) | The delivery harness — convergence loop to verified completion ⭐ |
21
+ | [**What UAP Does Automatically**](guides/AUTOMATIC_FEATURES.md) | Every feature in benefit / when-it-kicks-in terms — install once, it all self-applies ⭐ |
22
+ | [**`uap deliver`**](guides/DELIVER.md) | The delivery harness — verified changes via convergence loop ⭐ |ess — convergence loop to verified completion ⭐ |
23
23
  | [Memory](guides/MEMORY.md) | The 4-tier memory system, write-gates, semantic recall |
24
24
  | [MCP Router](guides/MCP_ROUTER.md) | Token-optimizing tool proxy + FTS5 output compression |
25
25
  | [Worktree Workflow](guides/WORKTREE_WORKFLOW.md) | Branch-per-feature isolation, auto-PR, enforcement |
@@ -1,92 +1,286 @@
1
- # What UAP Does For You — Automatically
1
+ # What UAP Does Automatically
2
2
 
3
- > The whole point of UAP: **you install it once, and every feature applies itself
4
- > as you code.** You don't call commands or remember protocols. UAP watches the
5
- > coding agent's lifecycle (session start, every prompt, every tool call, every
6
- > stop) and injects the right help or enforces the right guardrail *at the moment
7
- > it's needed*.
3
+ > **Install once. Every feature kicks in automatically.**
8
4
 
9
- ```bash
10
- npx @miller-tech/uap init # one-time, per project
11
- # …that's it. Open your coding agent and everything below is live.
5
+ UAP is not a set of manual steps you orchestrate. It is a **policy-and-resolver
6
+ layer** that sits between your coding agent (Claude Code, Opencode, Cursor,
7
+ Windsurf, Codex, etc.) and the model you use. Every feature below activates
8
+ **automatically** based on what the agent is doing — no config changes, no
9
+ manual triggers, no prompts to remember.
10
+
11
+ ---
12
+
13
+ ## How it works
14
+
15
+ When you start a coding session, UAP's hooks (installed by `uap setup`)
16
+ intercept every prompt the agent sends to the model. The **Reactor**
17
+ (`CapabilityRouter` + `PatternRouter`) evaluates the prompt in
18
+ real-time and, when appropriate, **injects** context, skills, or tool calls
19
+ into the agent's next turn. You never notice it happening — the agent just
20
+ produces better results.
21
+
22
+ ```
23
+ You → hook → UAP Reactor (auto-inject) → model → agent → better output
12
24
  ```
13
25
 
14
- `init`/`setup` wire UAP into whichever agent you use — Claude Code, Cursor,
15
- OpenCode, Factory, VSCode, Codex — by installing lifecycle hooks and the MCP
16
- router. After that the features are **on by default and apply themselves as
17
- appropriate**. Nothing here needs to be invoked by hand.
26
+ The confidence gate controls injection:
27
+
28
+ | Confidence | Behavior |
29
+ |---|---|
30
+ | ≥ 0.30 | Inject context/skills/experts into the prompt |
31
+ | ≥ 0.80 | Auto-spawn subagent with `uap deliver` for heavy lifting |
32
+ | < 0.30 | Pass through unchanged — zero overhead |
18
33
 
19
34
  ---
20
35
 
21
- ## How to read this
36
+ ## Every feature, when it kicks in
37
+
38
+ ### Reactor — Expert, Skill & Pattern Injection
22
39
 
23
- Two kinds of automatic behaviour, and they're deliberately different:
40
+ **Benefit:** Your model gets expert-level context for every prompt without you
41
+ having to craft the perfect system prompt.
24
42
 
25
- - **Assist** (dynamic, *helps* you): surfaces the right context experts,
26
- skills, patterns, memories by *injecting* it where the model will see it.
27
- It's confidence-gated, so quiet on conversational turns and rich on real
28
- coding tasks. It never blocks; worst case it stays silent.
29
- - **Enforce** (deterministic, *protects* you): hard guardrails that *block* a
30
- tool call when it would violate a rule (edit outside a worktree, skip
31
- delivery, run a dangerous command). Each has an escape hatch for the rare
32
- sanctioned exception.
43
+ **When it kicks in:** On every prompt the agent sends. The `CapabilityRouter`
44
+ matches the prompt against known droids (docker, infra, security, etc.) and
45
+ skills. The `PatternRouter` matches against a RAG-indexed library of proven
46
+ patterns. When confidence is 0.30, the relevant context is injected
47
+ automatically. When confidence is ≥ 0.80, a subagent is spawned to handle it
48
+ via `uap deliver`.
33
49
 
34
- For every feature below: **what it does for you**, and **when it kicks in**.
50
+ **You get:** Better code from any model even small local models because
51
+ they receive expert context they wouldn't otherwise have.
35
52
 
36
53
  ---
37
54
 
38
- ## Assistthe right help shows up on its own
55
+ ### Delivery Enforcement `uap deliver` for Verified Output
39
56
 
40
- | Feature | What it does for you | When it kicks in |
41
- |---|---|---|
42
- | **Reactor** (dynamic routing) | On every prompt, surfaces the expert droids, skills, and enforcement patterns relevant to *this* task, so the agent works like it already knows the domain. | Every substantive prompt (`UserPromptSubmit` / per-message). Confidence-gated — silent on "thanks"/"merge it", rich on "fix the auth race condition". |
43
- | **Memory recall** | Pulls back the lessons, decisions, and gotchas you (or another agent) learned before, so mistakes aren't repeated and context survives across sessions. | Session start (recent + high-importance memories) and per-prompt semantic recall on the task text. |
44
- | **Pattern RAG** | Injects battle-tested execution patterns (Output-Existence, Decoder-First, Round-Trip verify, …) mined from Terminal-Bench, so the agent uses the approach that actually passes. | Per-prompt, matched to the task; full set retrievable on demand via Qdrant. |
45
- | **Expert droids** | Routes domain work (security, performance, data, testing, …) to a specialist persona instead of a generalist guess. | When the capability router matches the task's type/files — recommended automatically, with optional auto-spawn above a confidence threshold. |
46
- | **Skills** | Surfaces the right *procedure* (git-forensics, compression, SQLite-WAL recovery, polyglot, …) for the task at hand. | Per-prompt match against the task; top-N surfaced. |
47
- | **Model routing** | Picks the right model tier per step (plan with the strong model, execute with the fast one) instead of one model for everything. | On task classification, by complexity and role. |
57
+ **Benefit:** Your agent's output is actually correct before it touches your
58
+ code. No more "it compiled but the tests fail" or "it broke the build."
48
59
 
49
- You don't ask for any of this. It appears in the agent's context the moment the
50
- task warrants it, and stays out of the way when it doesn't.
60
+ **When it kicks in:** Block-by-default. When the agent tries to edit source
61
+ files directly, the `delivery_enforcement` gate intercepts and routes the work
62
+ to `uap deliver` instead. The delivery harness runs a convergence loop: the
63
+ model iterates against real gates (build, typecheck, test) until everything
64
+ passes. Source-scoped: docs, configs, scripts, and tests are exempt (they
65
+ don't need delivery verification).
66
+
67
+ **Escape hatches:** `UAP_DELIVER_ACTIVE=1` to activate delivery for the
68
+ current session, `UAP_DELIVER_BYPASS=1` to skip enforcement,
69
+ `UAP_ENFORCE_DELIVERY=advisory` to downgrade from block to warning.
70
+
71
+ **You get:** Verified, working code from any model — including small local
72
+ models that would otherwise make mistakes.
51
73
 
52
74
  ---
53
75
 
54
- ## Enforcethe guardrails that keep work safe and verified
76
+ ### Memory4-Tier Auto-Recall
77
+
78
+ **Benefit:** Your coding agent remembers everything across sessions, projects,
79
+ and even different models. No more repeating yourself.
55
80
 
56
- | Feature | What it does for you | When it kicks in |
81
+ **When it kicks in:** On every prompt. The memory system has four tiers:
82
+
83
+ | Tier | What | How |
57
84
  |---|---|---|
58
- | **Delivery enforcement** (`uap deliver`, **block by default**) | Routes substantive coding through the **convergence loop** — which iterates a model against your real gates (build, type-check, tests) until the change is *verified*, not just plausible. This is what **uplifts small local models well above their weight**: a 3B-active model that would flail on one shot succeeds when driven to green against the gates. | The moment the agent tries to edit a **source** file directly. Docs/configs/scripts/tests are exempt — only real implementation work is gated. Escape: `UAP_DELIVER_BYPASS=1`, or relax with `UAP_ENFORCE_DELIVERY=advisory`. |
59
- | **Worktree isolation** | Forces code changes into an isolated `.worktrees/NNN-slug/` branch so you never clobber your working tree and every change is a clean, reviewable branch with an auto-PR. | Any source edit outside a worktree is blocked (`PreToolUse`). |
60
- | **Policy / compliance gates** | Block non-compliant tool calls before they run — dangerous shell (force-push, `terraform apply`), edits that skip a schema diff, plan-before-read violations, etc. | `PreToolUse` on every Edit/Write/Bash/Task call. |
61
- | **Schema-diff gate** | Flags breaking API/contract changes so you diff-and-verify consumers before shipping them. | After editing a schema/contract file (`*.schema.ts`, `types.ts`, `.proto`, `.graphql`, …). |
62
- | **Completion gates** | Won't let the agent declare "done" until build/type-check/tests actually pass and a version bump happened. | On `Stop` (end of turn). |
63
- | **Coordination** | Detects when multiple agents would touch the same files and prevents them stepping on each other. | Session start (register) + work announcement before claiming a task. |
64
- | **rtk token-optimization** | Rewrites heavy CLI output (git/docker/npm/…) into compact form so the agent burns far fewer tokens reading command output. | Every wrapped CLI command. |
65
- | **Deploy batching** | Queues changes into conflict-free batched commits/deploys instead of racy one-off pushes. | On `uap deliver --deploy` success. |
85
+ | L1 Semantic | Long-term project context | Nomic 768-dim embeddings, recalled via cosine similarity |
86
+ | L2 Episodic | Past conversations & decisions | Stored as episodes, recalled by semantic similarity |
87
+ | L3 Procedural | Commands, workflows, patterns | Stored as procedures, recalled when similar tasks arise |
88
+ | L4 Declarative | Facts, configs, references | Direct key-value store, recalled by key lookup |
66
89
 
67
- Each enforce-gate has a sanctioned escape hatch (an env var) for the rare case
68
- you genuinely need to bypass it so the guardrail is firm, not a cage.
90
+ **You get:** Context-aware coding that improves over time. The agent remembers
91
+ your conventions, past decisions, and project architecture without you
92
+ re-explaining.
69
93
 
70
94
  ---
71
95
 
72
- ## Behind it all
96
+ ### Patterns RAG — Proven Solutions on Demand
97
+
98
+ **Benefit:** Your agent applies battle-tested patterns instead of reinventing
99
+ solutions. Every pattern is indexed and retrieved automatically.
100
+
101
+ **When it kicks in:** When the agent encounters a problem that matches a stored
102
+ pattern. The PatternRouter uses semantic search to find the best-matching
103
+ pattern from the library and injects it into the prompt.
104
+
105
+ **You get:** Consistent, proven solutions across all agents and sessions.
106
+
107
+ ---
73
108
 
74
- | Feature | What it does for you | When it kicks in |
109
+ ### Worktree Enforcement
110
+
111
+ **Benefit:** Your main branch stays clean. Every change happens in an isolated
112
+ worktree with proper version bumps and merge commits.
113
+
114
+ **When it kicks in:** On every file edit. The worktree gate verifies you're
115
+ working inside a valid worktree before allowing source file edits. Docs,
116
+ configs, and scripts are exempt from this gate.
117
+
118
+ **You get:** Clean git history, proper versioning, and no accidental commits
119
+ to main.
120
+
121
+ ---
122
+
123
+ ### Policy Gates — Automated Safety
124
+
125
+ **Benefit:** Security, infrastructure parity, and delivery enforcement happen
126
+ automatically on every operation. No manual code reviews for common issues.
127
+
128
+ **When it kicks in:** On every tool use and CLI command:
129
+
130
+ | Gate | What it checks | When it fires |
75
131
  |---|---|---|
76
- | **MCP router** | Exposes a tiny meta-tool surface (`discover_tools`/`execute_tool`/`deliver`/`react`) instead of 150+ tools, cutting tool-schema tokens by ~98%. | Wired at install; used whenever the agent discovers/runs a tool. |
77
- | **HALO trace analysis** | Mines your execution traces for systemic failure modes (loops, stalls) so the harness gets better over time. | Session end / on demand (`uap harness analyze`). |
78
- | **4-tier memory** | Short-term (recent), long-term (semantic Qdrant), coordination, and patterns — the substrate the recall/pattern features draw from. | Continuously; written on significant decisions, read on recall. |
132
+ | rtk_wrap | Token optimization | Every CLI command |
133
+ | iac_parity | Infrastructure-as-Code safety | kubectl, helm, aws, gcloud, doctl |
134
+ | delivery_enforcement | Verified output | Every source file edit |
135
+
136
+ **You get:** Security and safety without manual intervention.
137
+
138
+ ---
139
+
140
+ ### Droids & Skills — Specialized Expertise
141
+
142
+ **Benefit:** Your agent has access to specialized experts (docker, infra,
143
+ security, etc.) without you having to prompt for them.
144
+
145
+ **When it kicks in:** When the agent encounters work that matches a droid's
146
+ domain. The CapabilityRouter detects the match and injects the droid's context
147
+ automatically.
148
+
149
+ **You get:** Expert-level output in specialized domains from any model.
79
150
 
80
151
  ---
81
152
 
82
- ## The one-liner
153
+ ### Skills — Dynamic Capability Injection
154
+
155
+ **Benefit:** New capabilities are injected on-demand based on the prompt
156
+ content. No configuration needed.
157
+
158
+ **When it kicks in:** When the prompt matches a registered skill. Skills are
159
+ matched semantically and injected automatically.
160
+
161
+ **You get:** A coding agent that grows smarter over time as new skills are
162
+ added.
163
+
164
+ ---
165
+
166
+ ### Coordination — Multi-Agent Orchestration
167
+
168
+ **Benefit:** Complex tasks are decomposed and executed automatically across
169
+ multiple agents with proper coordination.
170
+
171
+ **When it kicks in:** On complex prompts that benefit from multi-agent
172
+ parallelism. The coordinator decomposes the task, spawns parallel agents,
173
+ and merges results.
174
+
175
+ **You get:** Faster completion of complex tasks through parallel execution.
176
+
177
+ ---
83
178
 
84
- **Install UAP, then just code.** The assist layer makes your agent act like a
85
- domain expert with perfect recall; the enforce layer makes sure whatever it
86
- produces is isolated, verified, and safe and it drives even small local models
87
- to *verified* results they couldn't reach in one shot. You never invoke any of
88
- it; it applies itself, in the right place, at the right time.
179
+ ### MCP Router 98% Token Reduction
180
+
181
+ **Benefit:** Massive token savings on Model Context Protocol calls. Instead of
182
+ sending full tool schemas on every turn, the router caches and compresses them.
183
+
184
+ **When it kicks in:** On every MCP tool call. The router intercepts the call,
185
+ looks up the cached schema, and sends only the minimal necessary context.
186
+
187
+ **You get:** 98% fewer tokens on MCP operations — dramatic cost and latency
188
+ reduction.
189
+
190
+ ---
191
+
192
+ ### Schema-Diff Gate — API Contract Validation
193
+
194
+ **Benefit:** Schema changes are validated automatically. No more breaking API
195
+ contracts silently.
196
+
197
+ **When it kicks in:** When the agent edits schema files or API contract
198
+ definitions. The gate diffs the before/after and validates compatibility.
199
+
200
+ **You get:** Safe API evolution without manual review of every schema change.
201
+
202
+ ---
203
+
204
+ ### Completion Gates — Verify "Done" is Actually Done
205
+
206
+ **Benefit:** When the agent claims it's done, the gates verify: tests pass,
207
+ build succeeds, lint is clean, version is bumped.
208
+
209
+ **When it kicks in:** When the agent claims a task is complete. The gates run
210
+ automated verification before accepting the result.
211
+
212
+ **You get:** Confidence that "done" means actually done.
213
+
214
+ ---
215
+
216
+ ### Deploy Batching — Atomic Multi-Change Deploys
217
+
218
+ **Benefit:** Multiple related changes are deployed atomically. No partial
219
+ deploys that leave the system in an inconsistent state.
220
+
221
+ **When it kicks in:** When the agent prepares deployable changes. Related
222
+ changes are batched together and deployed as a single atomic unit.
223
+
224
+ **You get:** Reliable deploys with zero downtime.
225
+
226
+ ---
227
+
228
+ ### rtk — 60–90% Token Savings
229
+
230
+ **Benefit:** Massive token savings on every CLI command. rtk intercepts commands,
231
+ optimizes them, and proxies through a token-efficient layer.
232
+
233
+ **When it kicks in:** On every CLI command. rtk rewrites commands to use
234
+ optimized paths and caches results.
235
+
236
+ **You get:** Dramatically lower API costs and faster command execution.
237
+
238
+ ---
239
+
240
+ ### HALO — Human Oversight
241
+
242
+ **Benefit:** Critical operations require human approval before execution.
243
+ Automatic escalation when confidence is low.
244
+
245
+ **When it kicks in:** On critical operations (deployments, schema changes,
246
+ security-sensitive actions). HALO escalates to a human for approval.
247
+
248
+ **You get:** Safety for operations that matter, without slowing down routine
249
+ work.
250
+
251
+ ---
252
+
253
+ ## Local Models — Punching Above Their Weight
254
+
255
+ **Benefit:** Small local models (like Qwen3.6-35B-A3B running on consumer
256
+ hardware) produce code quality that rivals much larger models.
257
+
258
+ **How:** UAP's `uap deliver` convergence loop, expert injection, and pattern
259
+ RAG compensate for the smaller model's limitations. The model iterates against
260
+ real gates (build, test, typecheck) until everything passes.
261
+
262
+ **See:** [Local Models Guide](./LOCAL_MODELS.md) for setup instructions and
263
+ VRAM-tiered configurations.
264
+
265
+ ---
266
+
267
+ ## Quick Reference
268
+
269
+ | Feature | Benefit | Trigger |
270
+ |---|---|---|
271
+ | Reactor | Expert context for every prompt | Every prompt |
272
+ | Delivery Enforcement | Verified, working code | Every source edit |
273
+ | Memory | Remembers everything | Every prompt |
274
+ | Patterns RAG | Proven solutions | Pattern match |
275
+ | Worktree Enforcement | Clean git history | Every file edit |
276
+ | Policy Gates | Security & safety | Every tool/CLI |
277
+ | Droids & Skills | Specialized expertise | Domain match |
278
+ | Coordination | Parallel task execution | Complex tasks |
279
+ | MCP Router | 98% token reduction | Every MCP call |
280
+ | Schema-diff | API contract safety | Schema edits |
281
+ | Completion gates | Verify "done" is done | Agent claims done |
282
+ | Deploy batching | Atomic multi-change deploys | Deployable changes |
283
+ | rtk | 60–90% token savings | Every CLI command |
284
+ | HALO | Human oversight for critical ops | Critical actions |
89
285
 
90
- See also: [`uap deliver`](DELIVER.md) · [Local Models](LOCAL_MODELS.md) ·
91
- [Droids & Skills](DROIDS_AND_SKILLS.md) · [Policies](POLICIES.md) ·
92
- the [Reactor design](../design/UAP_REACTOR.md).
286
+ **Install UAP. Use your coding agent normally. Everything else is automatic.**
@@ -0,0 +1,164 @@
1
+ # UAP Automatic Features — What Fires When
2
+
3
+ Install UAP (`npm i -g universal-agent-protocol`) and every feature below activates automatically. There are no flags to set, no config to edit. UAP observes your workflow and injects the right capability at the right time.
4
+
5
+ ---
6
+
7
+ ## Per-Prompt Auto-Injection
8
+
9
+ ### Reactor — Expert Skills, Patterns & Droids
10
+ **What it does:** Every time you submit a coding prompt, the Reactor evaluates the request against a router of 25+ droids (experts), skill libraries, and implementation patterns. Relevant ones are injected into the agent's context automatically.
11
+
12
+ **When it kicks in:**
13
+ - You ask to "fix the auth flow" → AuthDroid + relevant skill templates load
14
+ - You need a migration → MigrationDroid + schema-diff pattern activate
15
+ - You're refactoring → RefactorDroid + pattern-RAG suggestions appear
16
+
17
+ **Why it matters:** Your model gets domain-specific expertise injected per-prompt without you having to prompt for it. Confidence-gated: low-confidence matches are suggested; high-confidence matches (≥0.80) auto-spawn as subagents.
18
+
19
+ ### Pattern RAG
20
+ **What it does:** Retrieves proven implementation patterns from the UAP pattern library based on your prompt's intent.
21
+
22
+ **When it kicks in:** Alongside Reactor evaluation — if your prompt matches a stored pattern (e.g., "add pagination", "implement rate limiting"), the pattern is injected as context.
23
+
24
+ **Why it matters:** Consistent, battle-tested implementations across every coding session. No reinventing the wheel.
25
+
26
+ ---
27
+
28
+ ## Policy Gates (Block-by-Default)
29
+
30
+ ### Delivery Enforcement
31
+ **What it does:** Prevents direct source-code edits by the model. Instead, routes changes through `uap deliver` — a convergence loop where the model iterates until real gates (build, typecheck, tests) pass.
32
+
33
+ **When it kicks in:** Any tool-use that touches source files (`.ts`, `.js`, `.py`, etc.). Docs, configs, scripts, tests, and `.worktrees/` are exempt (they don't need delivery).
34
+
35
+ **Why it matters:** Small models (Qwen3.6, Llama, etc.) frequently produce code that looks correct but doesn't compile. `uap deliver` catches this early — the model self-corrects through real compiler/test feedback until it actually works. Without it, broken code silently lands.
36
+
37
+ **Escape hatches:** `UAP_DELIVER_BYPASS=1` (one-shot), `UAP_DELIVER_ACTIVE=1` (session), `UAP_ENFORCE_DELIVERY=advisory` (warn-only).
38
+
39
+ ### Schema-Diff Gate
40
+ **What it does:** Before any schema or API contract change is applied, generates and validates a diff to ensure backward compatibility.
41
+
42
+ **When it kicks in:** When the model proposes changes to TypeScript interfaces, OpenAPI specs, database schemas, or any contract file.
43
+
44
+ **Why it matters:** Prevents silent API breakage that would crash downstream consumers.
45
+
46
+ ### Completion Gates
47
+ **What it does:** Before the model claims a task is "done," it must pass: build succeeds, tests pass, type-check clean, version bumped, self-reviewed.
48
+
49
+ **When it kicks in:** Automatically when the model attempts to mark a task complete.
50
+
51
+ **Why it matters:** Eliminates "it works on my machine" — every change is verified against the full test + build pipeline before being considered done.
52
+
53
+ ### Worktree Enforcement
54
+ **What it does:** Requires all source edits to happen inside isolated worktrees. Prevents accidental commits to the wrong branch.
55
+
56
+ **When it kicks in:** Any attempt to edit source files outside a worktree.
57
+
58
+ **Why it matters:** Clean git history, isolated feature branches, no accidental merges of incomplete work.
59
+
60
+ ---
61
+
62
+ ## Model Uplift
63
+
64
+ ### `uap deliver` — Convergence Loop
65
+ **What it does:** When delivery-enforcement routes a task to `uap deliver`, the tool runs a loop: the model produces code → real gates (build, typecheck, tests) validate → if anything fails, the error is fed back to the model → repeat until all gates pass.
66
+
67
+ **When it kicks in:** Automatically when delivery-enforcement blocks a direct source edit and the model needs to make actual code changes.
68
+
69
+ **Why it matters:** This is the single biggest uplift for small local models. A Qwen3.6-35B-A3B running locally with ~18GB VRAM will produce broken code on first try — but after 2-3 convergence iterations through real compiler feedback, it produces working code that matches what opus-4.8 would produce. The model learns from its mistakes in real-time.
70
+
71
+ ### Model Presets
72
+ **What it does:** Pre-configured model profiles in `src/models/types.ts` that set optimal parameters (temperature, max tokens, reasoning effort) per model.
73
+
74
+ **When it kicks in:** Automatically when you select a model. The `qwen35-a3b` preset is the default for local models.
75
+
76
+ **Why it matters:** No manual tuning. The right parameters are applied automatically for each model family.
77
+
78
+ ---
79
+
80
+ ## Memory & Context
81
+
82
+ ### Semantic Memory Recall
83
+ **What it does:** 4-tier memory system (short-term, long-term, episodic, semantic) with vector-based semantic search. Relevant memories are auto-recalled based on prompt context.
84
+
85
+ **When it kicks in:** Every prompt — the system searches memory for relevant past sessions, decisions, and patterns.
86
+
87
+ **Why it matters:** The agent remembers your project conventions, past decisions, and architectural choices across sessions. No re-explaining context.
88
+
89
+ ### MCP Router
90
+ **What it does:** Routes model tool calls through a centralized MCP (Model Context Protocol) router, reducing token usage by ~98% by batching and caching tool responses.
91
+
92
+ **When it kicks in:** Automatically for every tool call the model makes.
93
+
94
+ **Why it matters:** Massive token savings on repeated tool calls (file reads, git operations, etc.). Also enables consistent tool behavior across different models.
95
+
96
+ ---
97
+
98
+ ## Coordination & Multi-Agent
99
+
100
+ ### Coordination Layer
101
+ **What it does:** Orchestrates multi-agent workflows with deterministic control flow — fan-out, pipeline, barrier, and synthesis phases.
102
+
103
+ **When it kicks in:** When tasks are complex enough to warrant parallel subagents (e.g., "audit these 50 files" or "review changes across dimensions").
104
+
105
+ **Why it matters:** Parallel execution of independent tasks. A 10-file audit that would take 10 minutes sequentially completes in ~1 minute with 10 parallel agents.
106
+
107
+ ### Deploy Batching
108
+ **What it does:** Batches multiple changes into a single deploy operation, reducing deploy overhead and ensuring atomicity.
109
+
110
+ **When it kicks in:** When multiple independent changes are ready for deployment.
111
+
112
+ **Why it matters:** Fewer deploys, faster delivery, atomic rollouts.
113
+
114
+ ---
115
+
116
+ ## Developer Experience
117
+
118
+ ### RTK (Rust Token Killer)
119
+ **What it does:** CLI proxy that intercepts common commands (`git status`, `npm install`, etc.) and rewrites them for token efficiency — 60-90% token savings on dev operations.
120
+
121
+ **When it kicks in:** Automatically for every shell command you run. No flags needed.
122
+
123
+ **Why it matters:** Token costs add up fast. RTK transparently optimizes every command without you thinking about it.
124
+
125
+ ### HALO (High-Level Agent Orchestrator)
126
+ **What it does:** Provides a high-level orchestration layer for complex multi-step tasks, automatically decomposing them into subtasks and managing dependencies.
127
+
128
+ **When it kicks in:** When prompts are complex enough to warrant decomposition (substantial coding prompts, architectural changes, multi-file refactors).
129
+
130
+ **Why it matters:** You describe the goal, not the steps. HALO figures out the plan and executes it.
131
+
132
+ ---
133
+
134
+ ## Local Model Setup
135
+
136
+ ### llama.cpp + Qwen3.6-35B-A3B
137
+ **What it does:** Continuity server script (`scripts/run-llama-server-continuity.sh`) launches llama.cpp with optimal settings for the Qwen3.6-35B-A3B MoE model.
138
+
139
+ **When it kicks in:** When you need a local model for `uap deliver` convergence or as a coding agent backend.
140
+
141
+ **Why it matters:** See [Local Models](./LOCAL_MODELS.md) for VRAM-tiered setup instructions (8GB through 32GB). Key insight: `uap deliver` uplifts small models to punch well above their weight — a 35B-A3B running locally with real compiler feedback produces code quality comparable to much larger models.
142
+
143
+ ---
144
+
145
+ ## Summary Table
146
+
147
+ | Feature | Auto? | Triggers On | Benefit |
148
+ |---------|-------|-------------|---------|
149
+ | Reactor (experts/skills/patterns) | ✅ | Every prompt | Domain expertise injected per-request |
150
+ | Delivery enforcement | ✅ | Source edits | Small models self-correct through real gates |
151
+ | `uap deliver` convergence | ✅ | When delivery routes | Broken code fixed before landing |
152
+ | Schema-diff gate | ✅ | Contract changes | No silent API breakage |
153
+ | Completion gates | ✅ | Task completion | Verified before "done" |
154
+ | Worktree enforcement | ✅ | Source edits | Clean git history |
155
+ | Semantic memory | ✅ | Every prompt | Context remembered across sessions |
156
+ | MCP router | ✅ | Every tool call | ~98% token reduction |
157
+ | Pattern RAG | ✅ | Every prompt | Battle-tested implementations |
158
+ | Coordination | ✅ | Complex tasks | Parallel subagent execution |
159
+ | Deploy batching | ✅ | Multiple changes | Atomic, efficient deploys |
160
+ | RTK | ✅ | Every command | 60-90% token savings |
161
+ | HALO | ✅ | Substantial prompts | Automatic task decomposition |
162
+ | Model presets | ✅ | Model selection | Optimal params per model |
163
+
164
+ **Bottom line:** Install UAP, point it at your model (Claude Opus, Qwen3.6, Llama — any), and everything just works. No configuration required.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miller-tech/uap",
3
- "version": "1.46.4",
3
+ "version": "1.46.7",
4
4
  "description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -150,6 +150,15 @@ PROXY_LOOP_REPEAT_THRESHOLD = int(os.environ.get("PROXY_LOOP_REPEAT_THRESHOLD",
150
150
  PROXY_CYCLE_TRIGGER_REPEAT = int(os.environ.get("PROXY_CYCLE_TRIGGER_REPEAT", "3"))
151
151
  PROXY_FORCED_THRESHOLD = int(os.environ.get("PROXY_FORCED_THRESHOLD", "15"))
152
152
  PROXY_NO_PROGRESS_THRESHOLD = int(os.environ.get("PROXY_NO_PROGRESS_THRESHOLD", "3"))
153
+ # Fix D: streak-independent escape hatch. `no_progress_streak` resets to 0 on
154
+ # every turn whose last user message carries a tool_result (line ~3835) — i.e.
155
+ # every turn of a normal agentic loop — so the no_progress-gated LOOP BREAKER
156
+ # patterns can never accumulate. After this many *consecutive* forced-'required'
157
+ # turns (which DOES accumulate across an agentic loop via consecutive_forced_count),
158
+ # release tool_choice to 'auto' regardless of no_progress_streak so the model can
159
+ # emit a terminating response. Set well above any healthy run length (healthy
160
+ # loops hit auto/finalize/review phases that reset the count). 0 disables.
161
+ PROXY_FORCED_HARD_RELEASE = int(os.environ.get("PROXY_FORCED_HARD_RELEASE", "30"))
153
162
  PROXY_CONTEXT_RELEASE_THRESHOLD = float(
154
163
  os.environ.get("PROXY_CONTEXT_RELEASE_THRESHOLD", "0.90")
155
164
  )
@@ -258,6 +267,34 @@ PROXY_FINALIZE_SESSION_HARD_CAP = int(
258
267
  PROXY_RECON_CONVERGENCE_THRESHOLD = int(
259
268
  os.environ.get("PROXY_RECON_CONVERGENCE_THRESHOLD", "40")
260
269
  )
270
+ # Fix E: the recon hard tier (streak >= 2x threshold) fires a directive + flips
271
+ # tool_choice to 'auto', but `consecutive_no_write_turns` resets to 0 whenever
272
+ # the model emits any write tool — so a loop that periodically writes sawtooths
273
+ # the streak (observed: 90 -> 0 -> climb again), re-triggering the hard tier
274
+ # forever and never actually terminating. This counts how many times the hard
275
+ # tier has fired across the whole session (monotonic, never reset). Once it
276
+ # reaches this cap, the guard escalates: it strips tools for the turn so the
277
+ # model is forced to emit a terminal prose summary, breaking the sawtooth. 0
278
+ # disables the escalation (hard tier still flips to 'auto' each time).
279
+ PROXY_RECON_SESSION_HARD_CAP = int(
280
+ os.environ.get("PROXY_RECON_SESSION_HARD_CAP", "3")
281
+ )
282
+ # Fix F: context death-spiral breaker. When the *raw* (pre-prune) incoming
283
+ # context stays catastrophically over the window for several consecutive turns,
284
+ # releasing tool_choice to 'auto' (Fix B / LOOP BREAKER) is NOT enough — the
285
+ # model keeps voluntarily emitting tool calls and the client keeps resending an
286
+ # ever-growing transcript (observed: ctx 936%, model emits tool_calls 18/min
287
+ # despite tool_choice=auto). After this many consecutive turns at/above the
288
+ # ratio, strip tools entirely so the only possible response is a terminal text
289
+ # summary (end_turn), which ends the client's agentic loop. Ratio is set high
290
+ # enough that only a true runaway trips it — a merely-full session tops out near
291
+ # 100-130%, never 300%. 0 disables.
292
+ PROXY_RAW_CTX_FINALIZE_RATIO = float(
293
+ os.environ.get("PROXY_RAW_CTX_FINALIZE_RATIO", "3.0")
294
+ )
295
+ PROXY_RAW_CTX_FINALIZE_STREAK = int(
296
+ os.environ.get("PROXY_RAW_CTX_FINALIZE_STREAK", "2")
297
+ )
261
298
  PROXY_STREAM_REASONING_FALLBACK = (
262
299
  os.environ.get("PROXY_STREAM_REASONING_FALLBACK", "off").strip().lower()
263
300
  )
@@ -800,6 +837,13 @@ class SessionMonitor:
800
837
  last_input_tokens: int = 0 # Estimated input tokens of last request
801
838
  last_output_tokens: int = 0 # Actual output tokens of last response
802
839
  peak_input_tokens: int = 0 # High-water mark
840
+ # Fix B: the incoming (pre-prune) token count for the current request. The
841
+ # proxy prunes the conversation and then calls record_request() again with
842
+ # the post-prune total, so last_input_tokens / get_utilization() reflect the
843
+ # *pruned* size (~30%) by the time the tool_choice guards run — masking the
844
+ # fact that the client just sent e.g. 800% of the window. This preserves the
845
+ # raw size so LOOP BREAKER pattern 3 can release on real context blow-up.
846
+ pre_prune_input_tokens: int = 0
803
847
  prune_count: int = 0 # How many times pruning was triggered
804
848
  overflow_count: int = 0 # How many context overflow errors caught
805
849
  prune_drop_count: int = 0 # monotonic: # of oldest middle msgs pruned (B3)
@@ -818,6 +862,8 @@ class SessionMonitor:
818
862
  loop_warnings_emitted: int = 0 # How many loop warnings sent to the model
819
863
  no_progress_streak: int = 0 # Forced tool turns without new tool_result
820
864
  consecutive_no_write_turns: int = 0 # turns exploring with no write tool (B1)
865
+ recon_hard_fires: int = 0 # Fix E: monotonic count of recon hard-tier firings
866
+ catastrophic_ctx_streak: int = 0 # Fix F: consecutive turns raw ctx >= finalize ratio
821
867
  unexpected_end_turn_count: int = 0 # end_turn without tool_use in active loop
822
868
  tool_starvation_streak: int = 0 # Consecutive forced turns with no tool_calls produced
823
869
  malformed_tool_streak: int = 0 # consecutive malformed pseudo tool payloads
@@ -878,6 +924,18 @@ class SessionMonitor:
878
924
  return 0.0
879
925
  return self.last_input_tokens / self.context_window
880
926
 
927
+ def get_raw_utilization(self) -> float:
928
+ """Pre-prune context utilization for the current request (Fix B).
929
+
930
+ Reflects what the client actually sent this turn, before the proxy
931
+ pruned it. Used by the loop breaker so a runaway client that resends
932
+ 800% of the window each turn is detected even though post-prune
933
+ utilization reads ~30%. Returns 0.0 until the first request is recorded.
934
+ """
935
+ if self.context_window <= 0:
936
+ return 0.0
937
+ return self.pre_prune_input_tokens / self.context_window
938
+
881
939
  def get_warning_level(self) -> str | None:
882
940
  """Return warning level based on context utilization.
883
941
  Returns None if no warning needed."""
@@ -1238,12 +1296,37 @@ class SessionMonitor:
1238
1296
  self.loop_warnings_emitted += 1
1239
1297
  return True
1240
1298
 
1241
- # Pattern 3: Context almost full -- let model wrap up naturally
1242
- if self.get_utilization() >= PROXY_CONTEXT_RELEASE_THRESHOLD:
1299
+ # Pattern 2b (Fix D): streak-independent forced-count ceiling. In an
1300
+ # agentic loop no_progress_streak resets every turn (tool_result always
1301
+ # present), so Pattern 2 never fires. consecutive_forced_count, however,
1302
+ # accumulates across the loop. Release once it crosses the hard ceiling
1303
+ # regardless of no_progress_streak so the model can terminate.
1304
+ if (
1305
+ PROXY_FORCED_HARD_RELEASE > 0
1306
+ and self.consecutive_forced_count >= PROXY_FORCED_HARD_RELEASE
1307
+ ):
1308
+ logger.warning(
1309
+ "LOOP BREAKER: %d consecutive forced tool_choice requests (hard ceiling %d) -- "
1310
+ "releasing to 'auto' regardless of progress streak.",
1311
+ self.consecutive_forced_count,
1312
+ PROXY_FORCED_HARD_RELEASE,
1313
+ )
1314
+ self.loop_warnings_emitted += 1
1315
+ return True
1316
+
1317
+ # Pattern 3: Context almost full -- let model wrap up naturally.
1318
+ # Fix B: check BOTH post-prune utilization and the raw pre-prune size.
1319
+ # The proxy prunes before this runs, so get_utilization() reads ~30%
1320
+ # even when the client just sent 800% of the window; get_raw_utilization()
1321
+ # exposes the real blow-up so a runaway client is actually released.
1322
+ eff_util = max(self.get_utilization(), self.get_raw_utilization())
1323
+ if eff_util >= PROXY_CONTEXT_RELEASE_THRESHOLD:
1243
1324
  logger.warning(
1244
- "LOOP BREAKER: Context utilization %.1f%% -- releasing "
1245
- "tool_choice to let model wrap up.",
1325
+ "LOOP BREAKER: Context utilization %.1f%% (post-prune %.1f%%, raw %.1f%%) -- "
1326
+ "releasing tool_choice to let model wrap up.",
1327
+ eff_util * 100,
1246
1328
  self.get_utilization() * 100,
1329
+ self.get_raw_utilization() * 100,
1247
1330
  )
1248
1331
  return True
1249
1332
 
@@ -3397,8 +3480,32 @@ def _maybe_inject_recon_convergence(
3397
3480
  streak = monitor.consecutive_no_write_turns
3398
3481
  if streak < PROXY_RECON_CONVERGENCE_THRESHOLD:
3399
3482
  return
3400
- util = monitor.get_utilization()
3401
- if streak >= 2 * PROXY_RECON_CONVERGENCE_THRESHOLD:
3483
+ # Report the *raw* (pre-prune) utilization — post-prune util understates the
3484
+ # blow-up (~30%) and makes the directive's "context is at X%" misleading.
3485
+ util = max(monitor.get_utilization(), monitor.get_raw_utilization())
3486
+ hard = streak >= 2 * PROXY_RECON_CONVERGENCE_THRESHOLD
3487
+ escalate = False
3488
+ if hard:
3489
+ monitor.recon_hard_fires += 1 # Fix E: monotonic, never reset
3490
+ escalate = (
3491
+ PROXY_RECON_SESSION_HARD_CAP > 0
3492
+ and monitor.recon_hard_fires >= PROXY_RECON_SESSION_HARD_CAP
3493
+ )
3494
+
3495
+ if escalate:
3496
+ # Fix E: the hard tier has fired repeatedly this session — the model
3497
+ # keeps writing just enough to reset consecutive_no_write_turns, then
3498
+ # re-diverges, sawtoothing the streak and re-triggering the hard tier
3499
+ # forever. Stop negotiating: strip tools so the model MUST emit a
3500
+ # terminal plain-text summary, breaking the sawtooth for good.
3501
+ directive = (
3502
+ f"STOP. You have hit the exploration limit {monitor.recon_hard_fires} "
3503
+ f"times in this session and context is at {util * 100:.0f}%. No tools "
3504
+ "are available this turn. Reply NOW with a plain-text summary of what "
3505
+ "you found and what remains — this ends the task."
3506
+ )
3507
+ tier = "hard-escalated"
3508
+ elif hard:
3402
3509
  directive = (
3403
3510
  f"STOP exploring. You have run {streak} consecutive turns of "
3404
3511
  f"exploration without producing a deliverable and context is at "
@@ -3421,27 +3528,43 @@ def _maybe_inject_recon_convergence(
3421
3528
  msgs.append({"role": "user", "content": directive})
3422
3529
  openai_body["messages"] = msgs
3423
3530
 
3424
- # Re-inject any write/deliverable tool that narrowing dropped, so the
3425
- # "write your deliverable" directive is actually satisfiable. Without
3426
- # this the model is told to write but has no write tool to call, picks
3427
- # another read tool, and the streak climbs unbounded.
3428
3531
  restored: list[str] = []
3429
- if full_tools:
3430
- present = {
3431
- (t.get("function", {}).get("name", "") or "").lower()
3432
- for t in openai_body.get("tools", [])
3433
- }
3434
- for tool in full_tools:
3435
- name = (tool.get("function", {}).get("name", "") or "")
3436
- if name.lower() in _WRITE_TOOL_CLASS and name.lower() not in present:
3437
- openai_body.setdefault("tools", []).append(tool)
3438
- present.add(name.lower())
3439
- restored.append(name)
3532
+ if escalate:
3533
+ # Strip tools entirely so the only possible response is terminal prose.
3534
+ openai_body.pop("tools", None)
3535
+ openai_body.pop("tool_choice", None)
3536
+ openai_body.pop("grammar", None)
3537
+ else:
3538
+ if hard:
3539
+ # Fix C: at the hard tier, drop the structural requirement to call a
3540
+ # tool. Earlier logic forced tool_choice='required' for the active
3541
+ # agentic loop, which directly contradicts "produce your deliverable
3542
+ # NOW / do not run anything else" — the model is forbidden from
3543
+ # terminating and must emit yet another tool call, so the streak
3544
+ # climbs unbounded. Releasing to 'auto' lets it actually write/stop.
3545
+ openai_body["tool_choice"] = "auto"
3546
+ openai_body.pop("grammar", None)
3547
+ # Re-inject any write/deliverable tool that narrowing dropped, so the
3548
+ # "write your deliverable" directive is actually satisfiable. Without
3549
+ # this the model is told to write but has no write tool to call, picks
3550
+ # another read tool, and the streak climbs unbounded.
3551
+ if full_tools:
3552
+ present = {
3553
+ (t.get("function", {}).get("name", "") or "").lower()
3554
+ for t in openai_body.get("tools", [])
3555
+ }
3556
+ for tool in full_tools:
3557
+ name = (tool.get("function", {}).get("name", "") or "")
3558
+ if name.lower() in _WRITE_TOOL_CLASS and name.lower() not in present:
3559
+ openai_body.setdefault("tools", []).append(tool)
3560
+ present.add(name.lower())
3561
+ restored.append(name)
3440
3562
 
3441
3563
  logger.warning(
3442
- "RECON CONVERGENCE: injected %s directive (no_write_streak=%d, ctx=%.0f%%, "
3443
- "restored_write_tools=%s)",
3444
- tier, streak, util * 100, restored or "none",
3564
+ "RECON CONVERGENCE: injected %s directive (no_write_streak=%d, hard_fires=%d, "
3565
+ "ctx=%.0f%%, tool_choice=%s, restored_write_tools=%s)",
3566
+ tier, streak, monitor.recon_hard_fires, util * 100,
3567
+ openai_body.get("tool_choice", "stripped"), restored or "none",
3445
3568
  )
3446
3569
 
3447
3570
 
@@ -3751,6 +3874,46 @@ def build_openai_request(
3751
3874
  last_user_has_tool_result,
3752
3875
  )
3753
3876
 
3877
+ # CONTEXT DEATH-SPIRAL BREAKER (Fix F): raw incoming context has been
3878
+ # catastrophically over the window for several consecutive turns. The
3879
+ # LOOP BREAKER already released tool_choice to 'auto', but the model
3880
+ # keeps voluntarily emitting tool calls and the client keeps resending a
3881
+ # growing transcript, so the loop never ends. Strip tools entirely so
3882
+ # the only possible output is a terminal text summary (end_turn), which
3883
+ # ends the client's agentic loop. Gated high (raw ctx >= 300% for >= N
3884
+ # turns) so only a true runaway trips it, never a merely-full session.
3885
+ if (
3886
+ PROXY_RAW_CTX_FINALIZE_STREAK > 0
3887
+ and monitor.catastrophic_ctx_streak >= PROXY_RAW_CTX_FINALIZE_STREAK
3888
+ ):
3889
+ openai_body.pop("tool_choice", None)
3890
+ openai_body.pop("tools", None)
3891
+ openai_body.pop("grammar", None)
3892
+ msgs = openai_body.get("messages", [])
3893
+ msgs.append({
3894
+ "role": "user",
3895
+ "content": (
3896
+ "The conversation has exceeded the context window "
3897
+ f"({monitor.get_raw_utilization() * 100:.0f}%) and cannot "
3898
+ "continue. No tools are available. Reply with a brief "
3899
+ "plain-text summary of what was accomplished and what "
3900
+ "remains, then stop."
3901
+ ),
3902
+ })
3903
+ openai_body["messages"] = msgs
3904
+ monitor.reset_tool_turn_state(reason="context_death_spiral_breaker")
3905
+ logger.error(
3906
+ "CONTEXT DEATH-SPIRAL BREAKER: raw ctx %.0f%% for %d consecutive "
3907
+ "turns -- stripped tools to force terminal summary (end_turn).",
3908
+ monitor.get_raw_utilization() * 100,
3909
+ monitor.catastrophic_ctx_streak,
3910
+ )
3911
+ if PROXY_DISABLE_THINKING_ON_TOOL_TURNS:
3912
+ openai_body["enable_thinking"] = False
3913
+ if PROXY_DISABLE_SPEC_ON_TOOL_TURNS:
3914
+ openai_body["speculative.n_max"] = 0
3915
+ return openai_body
3916
+
3754
3917
  # TOOL STARVATION BREAKER: if model repeatedly fails to produce tool
3755
3918
  # calls despite required, strip tools to let it generate text and break
3756
3919
  # the forcing loop.
@@ -7834,6 +7997,20 @@ async def messages(request: Request):
7834
7997
  estimated_tokens,
7835
7998
  )
7836
7999
  utilization = effective_tokens / ctx_window
8000
+ # Fix B: preserve the raw incoming size before any pruning rewrites
8001
+ # last_input_tokens to the post-prune total, so the loop breaker can
8002
+ # see the true blow-up at build_openai_request time.
8003
+ monitor.pre_prune_input_tokens = effective_tokens
8004
+ # Fix F: track consecutive turns whose raw incoming context is
8005
+ # catastrophically over the window (a death spiral the per-request
8006
+ # pruner can mask but not cure). build_openai_request acts on this.
8007
+ if (
8008
+ PROXY_RAW_CTX_FINALIZE_RATIO > 0
8009
+ and utilization >= PROXY_RAW_CTX_FINALIZE_RATIO
8010
+ ):
8011
+ monitor.catastrophic_ctx_streak += 1
8012
+ else:
8013
+ monitor.catastrophic_ctx_streak = 0
7837
8014
  if utilization >= PROXY_CONTEXT_PRUNE_THRESHOLD:
7838
8015
  logger.warning(
7839
8016
  "Context utilization %.1f%% exceeds threshold %.1f%% -- pruning conversation",