ur-agent 1.65.6 → 1.65.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/CHANGELOG.md +52 -0
- package/README.md +5 -4
- package/dist/cli.js +5432 -3076
- package/dist/sdk/index.cjs +189 -0
- package/dist/sdk/index.d.ts +68 -0
- package/dist/sdk/index.js +149 -0
- package/docs/VALIDATION.md +1 -1
- package/documentation/app.js +91 -0
- package/documentation/index.html +1 -1
- package/extensions/jetbrains-ur/build.gradle.kts +1 -1
- package/extensions/vscode-ur-inline-diffs/package.json +1 -1
- package/package.json +13 -2
- package/technical/01-architecture.md +146 -0
- package/technical/02-cli-reference.md +227 -0
- package/technical/03-slash-commands.md +318 -0
- package/technical/04-tools.md +119 -0
- package/technical/05-providers-and-models.md +192 -0
- package/technical/06-configuration.md +407 -0
- package/technical/07-memory-and-context.md +147 -0
- package/technical/08-skills-plugins-workflows.md +211 -0
- package/technical/09-multi-agent.md +249 -0
- package/technical/10-headless-automation-eval.md +441 -0
- package/technical/11-integrations.md +156 -0
- package/technical/12-security-sandbox-stability.md +271 -0
- package/technical/13-research.md +129 -0
- package/technical/14-sessions.md +177 -0
- package/technical/README.md +43 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# 12 — Security, Sandbox & Stability
|
|
2
|
+
|
|
3
|
+
Source of truth: `src/utils/permissions/`, `src/utils/sandbox/`,
|
|
4
|
+
`src/entrypoints/sandboxTypes.ts`, `src/services/safety/projectSafety.ts`,
|
|
5
|
+
`src/security/`, `src/services/guardrails/guardrails.ts`, `src/stability/`,
|
|
6
|
+
`src/services/verifier/`, and `src/services/tools/toolHooks.ts`.
|
|
7
|
+
|
|
8
|
+
This chapter distinguishes an **enforced runtime boundary** from an
|
|
9
|
+
**inspection/advisory helper**. A command that can scan, classify, or print a
|
|
10
|
+
warning is not described as blocking ordinary agent execution unless it is
|
|
11
|
+
actually wired into that execution path.
|
|
12
|
+
|
|
13
|
+
## Permission engine — enforced
|
|
14
|
+
|
|
15
|
+
Every enabled tool call passes through the permission engine. Rules are loaded
|
|
16
|
+
from `permissions.allow`, `permissions.ask`, and `permissions.deny`, the
|
|
17
|
+
`--allowed-tools`/`--disallowed-tools` flags, session decisions, and managed
|
|
18
|
+
policy. Rule syntax is `Tool` or `Tool(specifier)`, for example
|
|
19
|
+
`Bash(git:*)`, `Edit(src/**)`, or `mcp__server__tool`.
|
|
20
|
+
|
|
21
|
+
User-addressable modes are:
|
|
22
|
+
|
|
23
|
+
| Mode | Runtime behavior |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `default` | Honor explicit rules and ask for undecided operations. |
|
|
26
|
+
| `plan` | Restrict mutation while planning. |
|
|
27
|
+
| `acceptEdits` | Auto-accept the supported edit path while retaining other checks. |
|
|
28
|
+
| `autoApprove` | Convert ordinary approval prompts to allow, except tools that require user interaction. Explicit deny rules and earlier safety checks still apply. |
|
|
29
|
+
| `bypassPermissions` | Broad bypass mode, but explicit ask rules and safety-check decisions that are marked bypass-immune can still prompt. Org/settings kill switches can disable the mode. |
|
|
30
|
+
|
|
31
|
+
`--dangerously-skip-permissions` selects bypass mode;
|
|
32
|
+
`--allow-dangerously-skip-permissions` makes that mode available to the
|
|
33
|
+
interactive selector. Managed settings can restrict permission rules, hooks,
|
|
34
|
+
and MCP servers to managed sources.
|
|
35
|
+
|
|
36
|
+
The normal external build does **not** enable the `TRANSCRIPT_CLASSIFIER`
|
|
37
|
+
feature. Its AI-classified `auto` mode is therefore source-only. The accepted
|
|
38
|
+
`permissions.classifierPermissionsEnabled` schema field is not read by a
|
|
39
|
+
shipped enforcement path and must not be treated as an active control.
|
|
40
|
+
|
|
41
|
+
Bash adds command parsing, command-injection checks, dangerous-pattern
|
|
42
|
+
classification, project safety policy, path validation, and sandbox-aware
|
|
43
|
+
permission decisions. `UR_CODE_DISABLE_COMMAND_INJECTION_CHECK` weakens one of
|
|
44
|
+
those checks and is not a safe default.
|
|
45
|
+
|
|
46
|
+
## OS sandbox — enforced when enabled and available
|
|
47
|
+
|
|
48
|
+
Set `sandbox.enabled` in settings to request OS-level Bash isolation. macOS uses
|
|
49
|
+
`/usr/bin/sandbox-exec`; Linux/WSL uses `bwrap`; Windows is unsupported. With
|
|
50
|
+
`sandbox.failIfUnavailable: false` (the default), an unavailable sandbox warns
|
|
51
|
+
and may run commands unsandboxed subject to permissions. Set
|
|
52
|
+
`failIfUnavailable: true` for a startup hard failure. The
|
|
53
|
+
`allowUnsandboxedCommands` policy controls whether a tool call may explicitly
|
|
54
|
+
request an unsandboxed run.
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
/sandbox status
|
|
58
|
+
/sandbox check
|
|
59
|
+
/sandbox init
|
|
60
|
+
/sandbox eval "curl https://example.com" --json
|
|
61
|
+
/sandbox exclude "npm run test:*"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The command surface is easy to misread:
|
|
65
|
+
|
|
66
|
+
- `status` and `check` inspect support/configuration.
|
|
67
|
+
- `init` writes `.ur/safety-policy.json`; it does **not** write or enable an OS
|
|
68
|
+
sandbox configuration.
|
|
69
|
+
- `eval` classifies a shell string through the project safety policy. It does
|
|
70
|
+
not execute the command.
|
|
71
|
+
- `/sandbox exclude "<pattern>"` is an interactive slash-command action. It
|
|
72
|
+
appends a non-duplicate pattern to `sandbox.excludedCommands` in the
|
|
73
|
+
project-local `.ur/settings.local.json`; the shell form `ur sandbox exclude`
|
|
74
|
+
is not implemented by the separate non-interactive command.
|
|
75
|
+
- An excluded match skips the OS sandbox for the entire Bash tool call. This is
|
|
76
|
+
a convenience exception, not a security boundary: it weakens isolation and
|
|
77
|
+
matching is heuristic. A compound call is excluded only when **every**
|
|
78
|
+
non-empty executable subcommand matches an exclusion; one unmatched segment
|
|
79
|
+
or a parse failure keeps the whole call sandboxed. Normal Bash permission
|
|
80
|
+
and safety-policy checks still apply:
|
|
81
|
+
exclusion does not itself grant tool permission.
|
|
82
|
+
|
|
83
|
+
Filesystem settings are merged with permission-derived paths. Existing parents
|
|
84
|
+
are canonicalized, sensitive UR/settings/skill paths are made non-writable, and
|
|
85
|
+
a sandbox-created bare-repository signature is scrubbed only when all required
|
|
86
|
+
signature paths appeared after the command.
|
|
87
|
+
|
|
88
|
+
Selective network-domain enforcement is not implemented by the compatibility
|
|
89
|
+
runtime. If allowed/denied domain lists are present, it fails closed by blocking
|
|
90
|
+
network for the sandboxed process instead of pretending to enforce host-level
|
|
91
|
+
filtering.
|
|
92
|
+
|
|
93
|
+
### Deny-default helper versus active profile
|
|
94
|
+
|
|
95
|
+
`buildSeatbeltProfile()` has a source-level `denyByDefault` option and also uses
|
|
96
|
+
a `(deny default)` profile when `allowRead` is non-empty. However,
|
|
97
|
+
`denyByDefault` is not part of `SandboxSettingsSchema`, and the shipped runtime
|
|
98
|
+
adapter does not pass it. With no `allowRead`, the macOS compatibility profile
|
|
99
|
+
uses `(allow default)` plus write/network/targeted denials. Therefore
|
|
100
|
+
`denyByDefault` is a tested builder capability, not a selectable shipped
|
|
101
|
+
setting. Linux `bwrap` separately mounts `/` read-only when no read allow-list
|
|
102
|
+
is supplied.
|
|
103
|
+
|
|
104
|
+
## Project shell safety policy — enforced for Bash
|
|
105
|
+
|
|
106
|
+
`.ur/safety-policy.json` classifies commands as read-only, project edits, safe
|
|
107
|
+
local commands, network operations, or destructive operations. Bash permission
|
|
108
|
+
checks consume this evaluation.
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
/safety status
|
|
112
|
+
/safety init
|
|
113
|
+
/safety check --command "rm -rf build" --json
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Untrusted-content framing — enforced on three channels
|
|
117
|
+
|
|
118
|
+
`src/security/promptInjection.ts` provides deterministic detection and framing,
|
|
119
|
+
not a proof that prompt injection is impossible.
|
|
120
|
+
|
|
121
|
+
| Function | What it does |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `scanForInjection(text)` | Detects seven instruction/exfiltration/boundary patterns plus hidden Unicode and reports a score. |
|
|
124
|
+
| `stripHiddenCharacters(text)` | Removes zero-width and bidirectional control characters. |
|
|
125
|
+
| `wrapUntrusted(text, source)` | Adds a random 128-bit nonce boundary, warning labels, and an in-memory source-ledger record. |
|
|
126
|
+
| `makeCanary()` / `canaryLeaked()` | Standalone canary helpers. |
|
|
127
|
+
|
|
128
|
+
The shipped automatic wrappers are exactly:
|
|
129
|
+
|
|
130
|
+
- `WebFetch` textual results;
|
|
131
|
+
- `WebSearch` formatted results (its citation reminder stays outside the data
|
|
132
|
+
boundary); and
|
|
133
|
+
- textual MCP tool-result blocks, except a tool explicitly marked as a trusted
|
|
134
|
+
control channel.
|
|
135
|
+
|
|
136
|
+
Local file reads, GitHub tool results, arbitrary user text, and every other
|
|
137
|
+
tool result do not pass through this wrapper merely because the module comment
|
|
138
|
+
mentions those threat classes. `makeCanary()` and `canaryLeaked()` are exported
|
|
139
|
+
helpers but are not installed in the main query/tool loop. `/sources` exposes
|
|
140
|
+
the bounded in-memory provenance created by actual `wrapUntrusted()` calls; it
|
|
141
|
+
does not prove that a model used a source to form a claim.
|
|
142
|
+
|
|
143
|
+
The durable boundaries remain permissions, OS sandboxing where enabled, scoped
|
|
144
|
+
credentials, and explicit human approval.
|
|
145
|
+
|
|
146
|
+
## Guardrails — manual checks plus two diff gates
|
|
147
|
+
|
|
148
|
+
Rules in `.ur/guardrails/*.json` support `regex`, `contains`, `pii`,
|
|
149
|
+
`maxLength`, `jsonSchema`, and `llm`; phases are `input`, `output`, or `both`;
|
|
150
|
+
actions are `warn` or `block`.
|
|
151
|
+
|
|
152
|
+
```text
|
|
153
|
+
/guardrails init
|
|
154
|
+
/guardrails list
|
|
155
|
+
/guardrails validate
|
|
156
|
+
/guardrails check "send this to x@y.com" --phase output --json
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`/guardrails check` evaluates the supplied text and reports a tripwire. The
|
|
160
|
+
engine is **not** a universal pre/post hook on every normal tool call. Its
|
|
161
|
+
deterministic diff-compatible rules are additionally wired into:
|
|
162
|
+
|
|
163
|
+
- `agent-task pr --create` self-review; and
|
|
164
|
+
- the Agent CI review path.
|
|
165
|
+
|
|
166
|
+
LLM and JSON-schema guardrails are not part of those diff gates. A blocking
|
|
167
|
+
finding prevents the relevant PR/CI handoff unless that command's explicit
|
|
168
|
+
override path is used; it does not globally stop unrelated agent activity.
|
|
169
|
+
|
|
170
|
+
## Security toolkit — deterministic/local commands
|
|
171
|
+
|
|
172
|
+
The `/security` family is a command toolkit, not a collection of automatically
|
|
173
|
+
invoked model tools:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
/security scan
|
|
177
|
+
/security code
|
|
178
|
+
/security secrets
|
|
179
|
+
/security report
|
|
180
|
+
/scope set local
|
|
181
|
+
/threat-model
|
|
182
|
+
/vuln
|
|
183
|
+
/ir
|
|
184
|
+
/compliance
|
|
185
|
+
/playbook
|
|
186
|
+
/harden
|
|
187
|
+
/kali
|
|
188
|
+
/lab create web-vuln
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Workspace code/secret scans are bounded heuristic scanners. `/vuln` consults
|
|
192
|
+
the dependency vulnerability implementation and can report no results when the
|
|
193
|
+
registry is unavailable. `/ir` and `/harden` are read-only collection/check
|
|
194
|
+
paths. `/scope` controls the security module's active web/testing operations;
|
|
195
|
+
it is separate from ordinary UR filesystem tool permissions. Lab creation
|
|
196
|
+
accepts only known templates and rejects unsafe roots.
|
|
197
|
+
|
|
198
|
+
The bundled `/security-review` skill is a model workflow prompt with explicit
|
|
199
|
+
verification and publishing instructions. Its existence does not turn the
|
|
200
|
+
security scanners into a universal automatic gate.
|
|
201
|
+
|
|
202
|
+
## Devcontainer target
|
|
203
|
+
|
|
204
|
+
`/devcontainer` is an explicit Docker-backed execution target described by
|
|
205
|
+
`.ur/devcontainer.json`:
|
|
206
|
+
|
|
207
|
+
```text
|
|
208
|
+
/devcontainer status
|
|
209
|
+
/devcontainer init --image node:22
|
|
210
|
+
/devcontainer exec -- npm test
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
It affects commands deliberately routed through the devcontainer command. It
|
|
214
|
+
does not transparently move every Bash/tool call into Docker.
|
|
215
|
+
|
|
216
|
+
## Stability ledger — recording is enforced; analysis is advisory
|
|
217
|
+
|
|
218
|
+
Normal tool start/finish hooks append action evidence to `.ur/actions.jsonl`.
|
|
219
|
+
The commands below inspect that ledger:
|
|
220
|
+
|
|
221
|
+
```text
|
|
222
|
+
/stability metrics
|
|
223
|
+
/stability firewall
|
|
224
|
+
/stability why "ECONNRESET"
|
|
225
|
+
/stability policy
|
|
226
|
+
/stability cooldown
|
|
227
|
+
/evidence 20
|
|
228
|
+
/actions 10
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`metrics`, `firewall`, `why`, and `cooldown` calculate failure, latency,
|
|
232
|
+
repetition, blast-radius, or likely-cause summaries. `firewall` prints an
|
|
233
|
+
advisory recommendation; it does not pause or cancel the core query loop.
|
|
234
|
+
`StabilityMonitor` is a self-contained source API and is not instantiated by
|
|
235
|
+
the normal query loop. This is a Monitor/Analyze evidence layer, not a fully
|
|
236
|
+
automatic MAPE-K controller.
|
|
237
|
+
|
|
238
|
+
## Verifier gates — separate enforced query-loop layer
|
|
239
|
+
|
|
240
|
+
The verifier is independent of `/stability`. In the default `strict` mode its
|
|
241
|
+
L1 query-loop checks include empty turns, repeated calls, completion claims
|
|
242
|
+
versus successful tool effects, unfinished actionable tasks, and configured or
|
|
243
|
+
auto-detected project gates after edits. Interactive sessions ask before
|
|
244
|
+
running project gates; non-interactive sessions can run them directly unless
|
|
245
|
+
`verifier.askBeforeGates` says otherwise. `UR_VERIFIER_MODE=loose|off` weakens
|
|
246
|
+
or disables these checks.
|
|
247
|
+
|
|
248
|
+
Immediate promises such as “let me create it now” are checked only in the final
|
|
249
|
+
visible clause and require matching successful mutation evidence. Rejections
|
|
250
|
+
are capped at three per user turn to avoid an infinite correction loop. The
|
|
251
|
+
independent L2 verification subagent is opt-in through `/verify` or
|
|
252
|
+
`UR_VERIFIER_AUTO_SUBAGENT=1`; it is not auto-spawned by default.
|
|
253
|
+
|
|
254
|
+
## Claim ledger and credentials
|
|
255
|
+
|
|
256
|
+
`/claim-ledger add` stores claim/source strings in
|
|
257
|
+
`.ur/evidence/claims.json` through the contained private-state writer (atomic
|
|
258
|
+
replacement, regular-file/symlink checks, `0600` mode, and a 2 MiB bound).
|
|
259
|
+
Loading is fail-closed: malformed JSON, a wrong root shape, duplicate IDs,
|
|
260
|
+
unsupported confidence/source kinds, or malformed records make `list`,
|
|
261
|
+
`validate`, and `add` fail nonzero; `add` never replaces the corrupt file with
|
|
262
|
+
an empty ledger. Source kinds are `web`, `file`, `mcp`, `tool`, and `user`.
|
|
263
|
+
`validate` checks only this stored structure; it does **not** fetch URLs, open files,
|
|
264
|
+
or prove that a source still resolves.
|
|
265
|
+
|
|
266
|
+
On macOS, credentials prefer Keychain and fall back to
|
|
267
|
+
`~/.ur/.credentials.json` when keychain reads/writes fail. On Linux and Windows,
|
|
268
|
+
the current implementation uses that plaintext JSON store directly. The file
|
|
269
|
+
is chmod `0600`, but it is still plaintext; “kept in the OS keychain” is not a
|
|
270
|
+
cross-platform guarantee. `/privacy-settings` and `--offline` control
|
|
271
|
+
telemetry/network behavior separately from credential storage.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# 13 — Research & File/Media Analysis
|
|
2
|
+
|
|
3
|
+
Source of truth: `src/services/agents/workingMode.ts`,
|
|
4
|
+
`src/constants/prompts.ts`, `src/ur/{notes,researchGraph,fileops,sysinfo}.ts`,
|
|
5
|
+
and `src/commands/{research,paper,cite,graph,read,search,index,summarize,analyze,convert,image,video,youtube,mode}/`.
|
|
6
|
+
|
|
7
|
+
## Working mode
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
/mode research
|
|
11
|
+
/mode code
|
|
12
|
+
/mode debug
|
|
13
|
+
/mode browser
|
|
14
|
+
/mode image
|
|
15
|
+
/mode video
|
|
16
|
+
/mode data
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The selected value is persisted in `.ur/mode`. `getWorkingModePrompt()` loads it
|
|
20
|
+
for the `working_mode` system-prompt section, so it changes the behavioral
|
|
21
|
+
instructions used on subsequent model turns. Invalid or unreadable values fall
|
|
22
|
+
back to `code`; changing the mode atomically writes a regular in-workspace
|
|
23
|
+
marker and clears the system-prompt section cache. A failed write returns
|
|
24
|
+
nonzero and leaves the previous marker intact.
|
|
25
|
+
|
|
26
|
+
This is prompt guidance, not a different model, tool registry, permission mode,
|
|
27
|
+
or deterministic workflow engine. Security-specific mode names are handled by
|
|
28
|
+
the separate security module.
|
|
29
|
+
|
|
30
|
+
## Notes, papers, and citations
|
|
31
|
+
|
|
32
|
+
| Command | Actual operation | Example |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `/research [note]` | Append a timestamped research note, or list notes. | `/research RAG eval baselines chosen` |
|
|
35
|
+
| `/paper [title or path]` | Append a paper string, or list papers. It does not parse a PDF. | `/paper papers/mamba.pdf` |
|
|
36
|
+
| `/cite [citation]` | Append a citation string, or list citations. It does not resolve or validate the citation. | `/cite Gu & Dao 2023` |
|
|
37
|
+
|
|
38
|
+
These are per-project file-backed collections under `.ur/`; they do not
|
|
39
|
+
automatically enter the model context merely because they were stored. Record
|
|
40
|
+
text is non-empty and capped at 64 KiB. The `.ur/research/` directories and
|
|
41
|
+
JSONL collection files must be regular in-workspace paths; symlinked storage,
|
|
42
|
+
read failures, and write failures return a nonzero command result rather than
|
|
43
|
+
claiming success.
|
|
44
|
+
|
|
45
|
+
## “Research graph”
|
|
46
|
+
|
|
47
|
+
`/graph` is currently a set of typed append-only JSONL collections under
|
|
48
|
+
`.ur/graph/`, not an edge-traversable graph database.
|
|
49
|
+
|
|
50
|
+
Supported entity names are `sources`, `papers`, `claims`, `methods`, `datasets`,
|
|
51
|
+
`metrics`, `limitations`, `citations`, `concepts`, `notes`, `experiments`,
|
|
52
|
+
`open_questions`, and `links`.
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
/graph
|
|
56
|
+
/graph papers
|
|
57
|
+
/graph papers Mamba: Linear-Time Sequence Modeling
|
|
58
|
+
/graph claims SSMs match attention at 1B scale
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
With no argument it reports per-collection counts. With an entity it lists
|
|
62
|
+
that collection. With an entity plus text it appends `{ts,text}`. Records do
|
|
63
|
+
not have IDs or validated links, so this surface must not be described as a
|
|
64
|
+
relational or knowledge graph. Writes are bounded, reject symlinked/outside
|
|
65
|
+
storage, and report a nonzero failure instead of claiming a record was saved.
|
|
66
|
+
|
|
67
|
+
## Text-file helpers
|
|
68
|
+
|
|
69
|
+
| Command | Operation |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `/read <path>` | Return a bounded text-like file to the user/model. |
|
|
72
|
+
| `/summarize <path>` | Return the bounded file prefixed with a summarization instruction. The model performs the summary. |
|
|
73
|
+
| `/analyze <path>` | Return the bounded file prefixed with an analysis instruction. The model performs the analysis. |
|
|
74
|
+
| `/search <query>` | Case-insensitive substring search across bounded workspace text files; at most 60 hits. |
|
|
75
|
+
| `/index` | Write a path-only workspace index to `.ur/index/files.txt`; this is not an embedding index. |
|
|
76
|
+
|
|
77
|
+
`/read`, `/summarize`, and `/analyze` accept the entire remaining command string
|
|
78
|
+
as the path, so workspace-relative paths containing spaces work without special
|
|
79
|
+
token parsing. `readFileSafe()` rejects absolute paths, `..`, directories,
|
|
80
|
+
binary extensions, and symlinks that resolve outside the workspace. Reads are
|
|
81
|
+
truncated at 64,000 characters by default.
|
|
82
|
+
|
|
83
|
+
`/search` and `/index` walk at most 8,000 entries and skip hidden entries other
|
|
84
|
+
than `.ur` plus common dependency/build directories. They are dependency-free
|
|
85
|
+
convenience helpers, not substitutes for the model tools `Grep`, `Glob`, or
|
|
86
|
+
semantic `CodeSearch`. The walker canonicalizes candidate files and skips
|
|
87
|
+
symlinks resolving outside the workspace. `/index` writes atomically beneath a
|
|
88
|
+
canonical in-workspace `.ur/index/` directory and returns nonzero if
|
|
89
|
+
`files.txt` cannot be persisted.
|
|
90
|
+
|
|
91
|
+
## Conversion and media commands
|
|
92
|
+
|
|
93
|
+
These commands have intentionally narrow behavior:
|
|
94
|
+
|
|
95
|
+
| Command | What it actually does |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `/convert <file> <target>` | Reports which of `pandoc`, `ffmpeg`, and `libreoffice` are installed. It does **not** execute a conversion or create an output file. |
|
|
98
|
+
| `/image <file> [task]` | Reports extension/size and, when `tesseract` exists, runs bounded OCR. It ignores the optional task text and does not invoke a vision model. |
|
|
99
|
+
| `/video <file\|url> [task]` | For a local file, reports bounded `ffprobe` format/stream metadata. For a URL, reports whether `yt-dlp` is installed. It does not extract frames/audio and ignores task text. |
|
|
100
|
+
| `/youtube <url> [task]` | Runs `yt-dlp --dump-json --skip-download` and prints selected metadata/description. It does not fetch subtitles/transcripts or summarize, and ignores task text. |
|
|
101
|
+
|
|
102
|
+
`/convert`, `/image`, `/video`, and `/youtube` take only the first whitespace
|
|
103
|
+
token as the file/URL (and `/convert` takes the second as target), so paths
|
|
104
|
+
containing spaces are not supported by those four parsers. Their output may
|
|
105
|
+
suggest asking the agent to use Bash or a vision-capable model for the next
|
|
106
|
+
step, but the local command itself has not performed that next step.
|
|
107
|
+
`/image` and `/video` also accept absolute paths and do not enforce workspace
|
|
108
|
+
containment.
|
|
109
|
+
|
|
110
|
+
`/os` reports presence of `git`, `ollama`, `node`, `bun`, `python3`, `ffmpeg`,
|
|
111
|
+
`yt-dlp`, `rg`, `cargo`, and `go`. `/ur-doctor` repeats that tool list, probes
|
|
112
|
+
the selected Ollama host, lists selected `.ur` assets, and checks for workspace
|
|
113
|
+
Playwright. Its current `mcp cfg` line checks legacy
|
|
114
|
+
`.ur/mcp/servers.toml` paths rather than the normal `.mcp.json`/settings MCP
|
|
115
|
+
sources, so it is not an authoritative MCP configuration diagnostic.
|
|
116
|
+
|
|
117
|
+
## Research-oriented bundled skills
|
|
118
|
+
|
|
119
|
+
The normal build registers these user-invocable prompt workflows:
|
|
120
|
+
|
|
121
|
+
- `/paper-implementation` (alias `/implement-paper`);
|
|
122
|
+
- `/latex-paper` (alias `/latex`); and
|
|
123
|
+
- `/benchmark` (aliases `/bench`, `/perf`).
|
|
124
|
+
|
|
125
|
+
Their prompts instruct the model to spawn an isolated worktree agent, gather
|
|
126
|
+
focused evidence, ask before a broader final verification sequence, and avoid
|
|
127
|
+
commit/push/PR publication unless separately requested. Those are agent
|
|
128
|
+
instructions, not a deterministic guarantee that the model completed every
|
|
129
|
+
step; verify the returned worktree, diff, and command evidence.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# 14 — Sessions, History & Recovery
|
|
2
|
+
|
|
3
|
+
Source of truth: `src/utils/{sessionStorage,sessionStoragePortable,fileHistory}.ts`,
|
|
4
|
+
`src/cost-tracker.ts`, `src/commands/{resume,rewind,branch,export,tag,rename,session,tasks,stats,cost,usage,files}/`,
|
|
5
|
+
`src/commands/bg/bg.ts`, `src/services/agents/backgroundRunner.ts`,
|
|
6
|
+
`src/cli/transports/{SSETransport,WebSocketTransport}.ts`, `src/tasks.ts`, and
|
|
7
|
+
`src/Task.ts`.
|
|
8
|
+
|
|
9
|
+
## Transcript persistence
|
|
10
|
+
|
|
11
|
+
Interactive sessions persist JSONL transcripts under
|
|
12
|
+
`~/.ur/projects/<sanitized-project-path>/<session-id>.jsonl`. Session name,
|
|
13
|
+
tag, mode, agent, worktree, and PR-link metadata are entries in that transcript.
|
|
14
|
+
`cleanupPeriodDays: 0`, `--no-session-persistence` in print mode, test mode, or
|
|
15
|
+
`UR_CODE_SKIP_PROMPT_HISTORY` suppresses transcript writes.
|
|
16
|
+
|
|
17
|
+
Cost is **not** stored independently in every transcript. The cost tracker saves
|
|
18
|
+
one “last session” cost/usage snapshot in the project entry of `~/.ur.json`; a
|
|
19
|
+
resume restores it only when that stored `lastSessionId` matches. Older
|
|
20
|
+
sessions can therefore have transcripts without a restorable cost snapshot.
|
|
21
|
+
|
|
22
|
+
## Continue and resume
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
ur -c
|
|
26
|
+
ur -r
|
|
27
|
+
ur -r 6f9d…
|
|
28
|
+
ur -r "auth refactor"
|
|
29
|
+
ur -c --fork-session
|
|
30
|
+
ur --from-pr 123
|
|
31
|
+
/resume [id or search]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- `-c` continues the most recent session for the project.
|
|
35
|
+
- `-r` opens the picker; its optional value is an ID or search term.
|
|
36
|
+
- `--fork-session` creates a new session ID while loading the prior
|
|
37
|
+
conversation.
|
|
38
|
+
- `--from-pr` resolves a transcript linked to a GitHub PR.
|
|
39
|
+
- `-n "name"` sets a startup title; `/rename` changes it later.
|
|
40
|
+
|
|
41
|
+
`/tag <name>` stores exactly one searchable tag on the current session.
|
|
42
|
+
Applying a different value replaces the prior tag; running the same value again
|
|
43
|
+
opens the removal confirmation. This is not a many-tags-per-session system.
|
|
44
|
+
|
|
45
|
+
Transcript appends use a single active drain with per-file FIFO queues. Failed
|
|
46
|
+
entries are restored ahead of later arrivals, the failure is retained until
|
|
47
|
+
`flush()` observes it, and a later `flush()` can retry after the underlying
|
|
48
|
+
filesystem problem is repaired. Session IDs used to construct transcript paths
|
|
49
|
+
must match the bounded alphanumeric/dash form.
|
|
50
|
+
|
|
51
|
+
## Transport recovery
|
|
52
|
+
|
|
53
|
+
For CCR-v2 remote sessions, `SSETransport` validates numeric sequence IDs,
|
|
54
|
+
requires contiguous delivery, advances its checkpoint only after delivering a
|
|
55
|
+
valid frame, and reconnects on malformed, mismatched, gapped, or incomplete
|
|
56
|
+
frames.
|
|
57
|
+
|
|
58
|
+
`WebSocketTransport` keeps a maximum of 1,000 meaningful outbound frames for
|
|
59
|
+
replay. On overflow it drops the oldest buffered frame and logs a diagnostic.
|
|
60
|
+
Reconnection replays buffered UUID messages and control frames that use
|
|
61
|
+
`request_id`. Frames remain buffered until a reconnect reports a last-received
|
|
62
|
+
UUID; confirming that UUID evicts it and every earlier buffered frame. A buffer
|
|
63
|
+
containing only control frames has no per-control acknowledgement key, so those
|
|
64
|
+
frames can replay again on later reconnects.
|
|
65
|
+
|
|
66
|
+
These are transport-level guarantees. They do not make an unavailable remote
|
|
67
|
+
service durable, and the direct-connect/remote-control launch commands are
|
|
68
|
+
source-only in the normal external bundle as described in chapter 11.
|
|
69
|
+
|
|
70
|
+
## Checkpoints, rewind, branches, and side chats
|
|
71
|
+
|
|
72
|
+
File-history snapshots are captured as agent edits occur.
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
/rewind
|
|
76
|
+
/checkpoint
|
|
77
|
+
/branch try-other-approach
|
|
78
|
+
/fork try-other-approach
|
|
79
|
+
/btw what's the difference between execa and spawn?
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`/rewind`/`/checkpoint` can restore conversation state, UR-managed file
|
|
83
|
+
snapshots, or both. These snapshots are separate from git commits.
|
|
84
|
+
|
|
85
|
+
`/branch`/`/fork` copies the persisted main-chain conversation into a new
|
|
86
|
+
session ID and switches to it; the optional argument is the branch session
|
|
87
|
+
title. `/btw` manages a durable side chat without replacing the main chain.
|
|
88
|
+
|
|
89
|
+
## Export and inspection
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
/export session.txt
|
|
93
|
+
/copy
|
|
94
|
+
/trace
|
|
95
|
+
/agent-inspect
|
|
96
|
+
/cost
|
|
97
|
+
/stats
|
|
98
|
+
/usage
|
|
99
|
+
/insights
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`/export [filename]` renders the same plain-text transcript for both supported
|
|
103
|
+
filename suffixes. Explicit `.txt` and `.md` suffixes are preserved, so
|
|
104
|
+
`/export session.md` writes `session.md`; `.md` does not select a separate
|
|
105
|
+
Markdown renderer. A missing suffix or any other suffix is normalized to
|
|
106
|
+
`.txt`. Without a filename, the interactive export dialog offers a generated
|
|
107
|
+
`.txt` name or clipboard behavior. File targets must be relative to the
|
|
108
|
+
workspace, their parent directory must already exist, and traversal or symlink
|
|
109
|
+
escapes are rejected.
|
|
110
|
+
|
|
111
|
+
`/cost` reports the in-memory current-session cost/duration for API-key/local
|
|
112
|
+
usage. For ordinary UR subscription users it reports subscription/overage state
|
|
113
|
+
instead of an exact dollar breakdown and is hidden from the slash menu.
|
|
114
|
+
`/stats` is an interactive activity view; `/usage` opens the Usage settings tab
|
|
115
|
+
for plan limits. They are not aliases for the same data.
|
|
116
|
+
|
|
117
|
+
`/files` lists the paths in the current read-file cache, but its command is
|
|
118
|
+
enabled only for `USER_TYPE=ant`; it is not available in the normal external
|
|
119
|
+
build. `/trace` and `/agent-inspect` expose recent/tool and subagent execution
|
|
120
|
+
views respectively.
|
|
121
|
+
|
|
122
|
+
## Detached background agents — shipped
|
|
123
|
+
|
|
124
|
+
The supported external command family is `ur bg`, not the source-only legacy
|
|
125
|
+
`--bg`, `ur ps`, `ur logs`, `ur attach`, and `ur kill` fast paths.
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
ur bg run "run the full test suite and summarize"
|
|
129
|
+
ur bg fanout "audit each package" --agents 3 --worktree
|
|
130
|
+
ur bg list
|
|
131
|
+
ur bg status <id>
|
|
132
|
+
ur bg logs <id> --tail 120
|
|
133
|
+
ur bg attach <id>
|
|
134
|
+
ur bg steer <id> --message "focus on the failing integration test"
|
|
135
|
+
ur bg kill <id>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`run` starts one detached child; `fanout` starts the requested bounded number.
|
|
139
|
+
`--worktree` is opt-in. `--pr` is also opt-in and is rejected without
|
|
140
|
+
`--worktree`; when supplied, it authorizes the background PR/push handoff
|
|
141
|
+
configured by the remaining PR flags. `--dry-run` records/plans the task without
|
|
142
|
+
spawning its worker.
|
|
143
|
+
|
|
144
|
+
State, logs, outputs, and idempotent steering inboxes live under the git/project
|
|
145
|
+
root's `.ur/background/`. The manifest is lock-protected and atomically
|
|
146
|
+
replaced. Steering applies only to queued/running tasks and is bounded to
|
|
147
|
+
64 KiB per message and 8 MiB per inbox.
|
|
148
|
+
|
|
149
|
+
The legacy `--bg` and process-level `ps|logs|attach|kill` fast paths are behind
|
|
150
|
+
the `BG_SESSIONS` build feature, which the normal external bundle does not
|
|
151
|
+
enable. They must not be documented as the supported npm command syntax.
|
|
152
|
+
|
|
153
|
+
## In-session tasks
|
|
154
|
+
|
|
155
|
+
`/tasks` (alias `/bashes`) opens the task dialog for the current process.
|
|
156
|
+
`TaskOutput` reads task output and `TaskStop` stops a supported running task.
|
|
157
|
+
The five creatable lifecycle implementations in the external runtime are:
|
|
158
|
+
|
|
159
|
+
- local shell;
|
|
160
|
+
- local agent;
|
|
161
|
+
- remote agent;
|
|
162
|
+
- in-process teammate; and
|
|
163
|
+
- dream.
|
|
164
|
+
|
|
165
|
+
`local_workflow` and `monitor_mcp` remain parseable/renderable historical task
|
|
166
|
+
types, but have no constructor or stop lifecycle in this distribution. A stop
|
|
167
|
+
request for them returns an explicit unsupported-type error.
|
|
168
|
+
|
|
169
|
+
## Multi-directory access and trust
|
|
170
|
+
|
|
171
|
+
- `/add-dir ../other-repo` or `--add-dir` extends the allowed working
|
|
172
|
+
directories; normal path/permission checks still apply.
|
|
173
|
+
- Interactive startup asks whether the workspace is trusted. Print mode skips
|
|
174
|
+
that dialog and therefore must be used only in a directory the caller already
|
|
175
|
+
trusts.
|
|
176
|
+
- `/ur-init` scaffolds UR project assets under `.ur/`; `/init` generates the
|
|
177
|
+
agent-instruction file (`UR.md`).
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# UR-Nexus — Technical Specifications
|
|
2
|
+
|
|
3
|
+
> Audited against the executable source and tests for `ur-agent` v1.65.7.
|
|
4
|
+
> Command, tool, flag, provider, and setting claims are checked against the
|
|
5
|
+
> implementation rather than copied from product prose. Release validation
|
|
6
|
+
> keeps this version synchronized and packages the complete `technical/`
|
|
7
|
+
> catalog with the npm artifact.
|
|
8
|
+
|
|
9
|
+
UR-Nexus is an autonomous engineering workflow engine: a terminal (Ink/React) coding agent
|
|
10
|
+
with a plan → execute → test → verify → document → benchmark loop, local/server model support
|
|
11
|
+
(Ollama, llama.cpp, and vLLM), cloud API providers (OpenAI, Anthropic, Gemini, OpenRouter,
|
|
12
|
+
and any OpenAI-compatible endpoint), a multi-agent orchestration layer, and a large built-in
|
|
13
|
+
command/tool surface. An LM Studio adapter remains in the registry but is explicitly disabled
|
|
14
|
+
in this release, so it is not advertised as an available backend.
|
|
15
|
+
|
|
16
|
+
## Document map
|
|
17
|
+
|
|
18
|
+
| File | Contents |
|
|
19
|
+
|---|---|
|
|
20
|
+
| [01-architecture.md](01-architecture.md) | Runtime architecture: entrypoints, REPL, query engine, task types, services |
|
|
21
|
+
| [02-cli-reference.md](02-cli-reference.md) | The `ur` binary: flags, subcommands, headless mode, background sessions |
|
|
22
|
+
| [03-slash-commands.md](03-slash-commands.md) | Every interactive slash command with usage examples |
|
|
23
|
+
| [04-tools.md](04-tools.md) | Every model-invocable tool (built-in + conditional) with schemas and examples |
|
|
24
|
+
| [05-providers-and-models.md](05-providers-and-models.md) | Provider registry, model selection, routing, escalation, effort/fast modes |
|
|
25
|
+
| [06-configuration.md](06-configuration.md) | settings.json schema, scopes, permission rules, env variables, keybindings |
|
|
26
|
+
| [07-memory-and-context.md](07-memory-and-context.md) | UR.md, auto-memory, /remember, semantic memory, knowledge base, context pack, compaction |
|
|
27
|
+
| [08-skills-plugins-workflows.md](08-skills-plugins-workflows.md) | Skills (SKILL.md), bundled skills, plugins/marketplaces, declarative workflows, patterns, toolsmith |
|
|
28
|
+
| [09-multi-agent.md](09-multi-agent.md) | Subagents, crews, arena, background agents, routing, escalation, worktrees per task |
|
|
29
|
+
| [10-headless-automation-eval.md](10-headless-automation-eval.md) | `-p` print mode, /exec, SDK, automations, triggers, CI loop, eval harness, benchmarks |
|
|
30
|
+
| [11-integrations.md](11-integrations.md) | MCP, IDE/ACP, A2A, Chrome, GitHub, Slack, remote control, desktop, voice |
|
|
31
|
+
| [12-security-sandbox-stability.md](12-security-sandbox-stability.md) | Permission system, sandbox, safety policy, guardrails, security toolkit, stability/MAPE-K |
|
|
32
|
+
| [13-research.md](13-research.md) | Research notes, papers, citations, research graph, file/media analysis commands |
|
|
33
|
+
| [14-sessions.md](14-sessions.md) | Session persistence, resume, rewind/checkpoints, branching, export, tags, insights |
|
|
34
|
+
|
|
35
|
+
## Quick facts (from code)
|
|
36
|
+
|
|
37
|
+
- **Package**: `ur-agent`, binary `ur` (`bin/ur.js` → `dist/cli.js`, bundled from `src/entrypoints/cli.tsx`).
|
|
38
|
+
- **Runtime**: the npm binary uses a Node ≥ 18.18 launcher and requires Bun ≥ 1.3 for the bundled CLI; the TUI uses React 19 and the vendored Ink fork in `src/ink`.
|
|
39
|
+
- **Local-first**: default model backend is the local Ollama runtime (`http://localhost:11434`); `--offline` disables all cloud paths.
|
|
40
|
+
- **Registered commands at this release**: 168 bundled registry entries, 161 visible entries, 237 visible slash invocation tokens, and 70 rows in `ur --help`; fast-path lifecycle/server commands are documented separately in doc 02. User/project skills, installed plugins, workflows, and MCP prompts are additive and normalized by source priority.
|
|
41
|
+
- **Registered tools**: the built-in pool is assembled per session from `src/tools.ts:getAllBaseTools()` and then filtered by runtime, mode, settings, permissions, and availability. Doc 04 enumerates the public built-ins and every supported gate; connected MCP tools are additive.
|
|
42
|
+
- **Feature flags**: compile-time `feature(...)` gates (`bun:bundle`) dead-code-eliminate internal-only surfaces from external builds; `USER_TYPE=ant` gates internal commands.
|
|
43
|
+
- **Project state**: lives under `.ur/` in each repo (artifacts, specs, workflows, guardrails, safety policy, knowledge, memory index, devcontainer config, tools, index).
|