@shanepadgett/tau-agent 0.25.1 → 0.27.0

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.
Files changed (32) hide show
  1. package/docs/subagents.md +1 -1
  2. package/extensions/appshot/README.md +1 -1
  3. package/extensions/appshot/index.ts +5 -11
  4. package/extensions/context-pruning/README.md +2 -2
  5. package/extensions/context-pruning/index.ts +58 -57
  6. package/extensions/context-pruning/render.ts +51 -39
  7. package/extensions/context-pruning/settings.ts +4 -5
  8. package/extensions/explore/README.md +18 -10
  9. package/extensions/explore/ast-guidance.ts +67 -0
  10. package/extensions/explore/ast-languages.ts +61 -0
  11. package/extensions/explore/ast-tools.ts +1597 -94
  12. package/extensions/explore/ast-worker.ts +768 -60
  13. package/extensions/explore/index.ts +62 -6
  14. package/extensions/explore/orientation-state.ts +280 -0
  15. package/extensions/explore/read-stats-panel.ts +23 -1
  16. package/extensions/explore/read-stats.ts +21 -3
  17. package/extensions/explore/read.ts +58 -21
  18. package/extensions/explore/settings.ts +46 -0
  19. package/extensions/explore/traverse.ts +15 -4
  20. package/extensions/patch/executor.ts +95 -1
  21. package/extensions/patch/index.ts +1 -0
  22. package/extensions/soul/prompt.ts +1 -3
  23. package/extensions/subagent/agents/review.md +76 -25
  24. package/extensions/subagent/agents/scout.md +118 -22
  25. package/extensions/subagent/session-resource.ts +1 -1
  26. package/extensions/tau-help/help.md +3 -1
  27. package/native-bin/darwin-arm64/tau-ast +0 -0
  28. package/package.json +2 -3
  29. package/schemas/tau.schema.json +44 -4
  30. package/shared/bounded-text-result.ts +304 -0
  31. package/shared/events.ts +2 -1
  32. package/shared/temporary-output-store.ts +275 -0
@@ -0,0 +1,46 @@
1
+ import { relative, resolve } from "node:path";
2
+ import { Type } from "typebox";
3
+ import { matchGlob, posixPath } from "../../shared/glob.ts";
4
+ import { defineTauExtensionSettings } from "../../shared/settings/define.ts";
5
+
6
+ export interface ExploreReadGateSettings {
7
+ includeGlobs: string[];
8
+ excludeGlobs: string[];
9
+ }
10
+
11
+ export default defineTauExtensionSettings({
12
+ key: "explore",
13
+ defaults: {
14
+ readGate: {
15
+ includeGlobs: ["**/*"] as string[],
16
+ excludeGlobs: ["**/*.md", "**/*.markdown", "**/*.mdown"] as string[],
17
+ },
18
+ },
19
+ schema: Type.Object(
20
+ {
21
+ readGate: Type.Object(
22
+ {
23
+ includeGlobs: Type.Array(Type.String(), {
24
+ default: ["**/*"],
25
+ description:
26
+ "Working-directory-relative supported source paths that require a structural attempt before read.",
27
+ }),
28
+ excludeGlobs: Type.Array(Type.String(), {
29
+ default: ["**/*.md", "**/*.markdown", "**/*.mdown"],
30
+ description: "Working-directory-relative paths excluded from the Explore read gate. Exclusions win.",
31
+ }),
32
+ },
33
+ { additionalProperties: false },
34
+ ),
35
+ },
36
+ { additionalProperties: false },
37
+ ),
38
+ });
39
+
40
+ export function matchesExploreReadGate(path: string, cwd: string, settings: ExploreReadGateSettings): boolean {
41
+ const projectPath = posixPath(relative(resolve(cwd), resolve(path)));
42
+ return (
43
+ settings.includeGlobs.some((pattern) => matchGlob(pattern, projectPath)) &&
44
+ !settings.excludeGlobs.some((pattern) => matchGlob(pattern, projectPath))
45
+ );
46
+ }
@@ -1,5 +1,5 @@
1
1
  import type { Stats } from "node:fs";
2
- import { lstat, readdir, readFile } from "node:fs/promises";
2
+ import { lstat, opendir, readFile } from "node:fs/promises";
3
3
  import { dirname, join, matchesGlob, resolve, sep } from "node:path";
4
4
  import { formatPathForDisplay, isWithinPath, relativeSlash, toSlashPath } from "./path-display.ts";
5
5
 
@@ -18,6 +18,7 @@ export interface CollectPathOptions {
18
18
  cwd: string;
19
19
  root: string;
20
20
  maxDepth?: number;
21
+ maxEntries?: number;
21
22
  includeRoot: boolean;
22
23
  includeHidden: boolean;
23
24
  includeIgnored: boolean;
@@ -149,9 +150,14 @@ function sortEntries(entries: TraversalEntry[]): TraversalEntry[] {
149
150
  });
150
151
  }
151
152
 
152
- async function readDirectoryNames(directory: string, cwd: string): Promise<string[]> {
153
+ async function readDirectoryNames(directory: string, cwd: string, limit: number | undefined): Promise<string[]> {
153
154
  try {
154
- return await readdir(directory);
155
+ const names: string[] = [];
156
+ for await (const entry of await opendir(directory)) {
157
+ names.push(entry.name);
158
+ if (limit !== undefined && names.length >= limit) break;
159
+ }
160
+ return names;
155
161
  } catch {
156
162
  throw new Error(`Cannot read directory: ${formatPathForDisplay(directory, cwd)}`);
157
163
  }
@@ -160,6 +166,7 @@ async function readDirectoryNames(directory: string, cwd: string): Promise<strin
160
166
  export async function collectPaths(options: CollectPathOptions): Promise<TraversalEntry[]> {
161
167
  const entries: TraversalEntry[] = [];
162
168
  const entryByPath = new Map<string, TraversalEntry>();
169
+ let inspectedEntries = 0;
163
170
  const rootStats = await lstat(options.root);
164
171
  const rootKind = entryKind(rootStats);
165
172
  const rootDirectory = rootKind === "dir" ? options.root : dirname(options.root);
@@ -183,13 +190,17 @@ export async function collectPaths(options: CollectPathOptions): Promise<Travers
183
190
 
184
191
  async function walkDirectory(directory: string, depth: number, rules: readonly IgnoreRule[]): Promise<number> {
185
192
  if (options.maxDepth !== undefined && depth >= options.maxDepth) return 0;
193
+ if (options.maxEntries !== undefined && inspectedEntries >= options.maxEntries) return 0;
186
194
 
187
- const names = await readDirectoryNames(directory, options.cwd);
195
+ const remaining = options.maxEntries === undefined ? undefined : options.maxEntries - inspectedEntries;
196
+ const names = await readDirectoryNames(directory, options.cwd, remaining);
188
197
 
189
198
  const children: TraversalEntry[] = [];
190
199
  for (const name of names) {
200
+ if (options.maxEntries !== undefined && inspectedEntries >= options.maxEntries) break;
191
201
  const childPath = `${directory}/${name}`;
192
202
  const stats = await lstat(childPath);
203
+ inspectedEntries += 1;
193
204
  const kind = entryKind(stats);
194
205
  if (shouldSkipPath(childPath, kind, rules, options)) continue;
195
206
  children.push({
@@ -1,4 +1,5 @@
1
- import { access, mkdir, readFile, rmdir, stat, unlink, writeFile } from "node:fs/promises";
1
+ import { createHash } from "node:crypto";
2
+ import { access, mkdir, readFile, realpath, rmdir, stat, unlink, writeFile } from "node:fs/promises";
2
3
  import { dirname, isAbsolute, relative, resolve } from "node:path";
3
4
  import { withFileMutationQueue } from "@earendil-works/pi-coding-agent";
4
5
  import { applyChunksWithRanges, countLogicalLines, UpdateChunkApplyError } from "./matcher.ts";
@@ -11,6 +12,7 @@ export interface ApplyPatchChange {
11
12
  move?: { from: string; to: string };
12
13
  linesAdded: number;
13
14
  linesRemoved: number;
15
+ resultingFingerprint: string | null;
14
16
  snapshotRanges?: Array<{ startLine: number; endLine: number }>;
15
17
  }
16
18
 
@@ -32,6 +34,12 @@ export interface ApplyPatchStats {
32
34
  completedOperations: number;
33
35
  }
34
36
 
37
+ export interface ExactSourceMutation {
38
+ path: string;
39
+ expectedFingerprint: string;
40
+ source: string;
41
+ }
42
+
35
43
  export function deriveStats(summary: ApplyPatchSummary): ApplyPatchStats {
36
44
  const added: string[] = [];
37
45
  const replaced: string[] = [];
@@ -80,6 +88,10 @@ function throwIfAborted(signal: AbortSignal | undefined): void {
80
88
  if (signal?.aborted) throw new Error("Operation aborted");
81
89
  }
82
90
 
91
+ function fingerprint(source: string): string {
92
+ return `sha256:${createHash("sha256").update(source, "utf8").digest("hex")}`;
93
+ }
94
+
83
95
  async function pathExists(path: string): Promise<boolean> {
84
96
  try {
85
97
  await access(path);
@@ -136,6 +148,7 @@ async function stageWholeFile(
136
148
  path: op.path,
137
149
  linesAdded: op.linesAdded,
138
150
  linesRemoved,
151
+ resultingFingerprint: fingerprint(op.content),
139
152
  snapshotRanges: lineCount > 0 ? [{ startLine: 1, endLine: Math.min(lineCount, 120) }] : undefined,
140
153
  },
141
154
  async commit() {
@@ -156,6 +169,7 @@ async function stageDelete(cwd: string, op: Extract<PatchOperation, { type: "del
156
169
  path: op.path,
157
170
  linesAdded: 0,
158
171
  linesRemoved: countLogicalLines(current),
172
+ resultingFingerprint: null,
159
173
  },
160
174
  async commit() {
161
175
  await unlink(target);
@@ -180,6 +194,7 @@ async function stageUpdate(cwd: string, op: Extract<PatchOperation, { type: "upd
180
194
  path: op.path,
181
195
  linesAdded: op.linesAdded,
182
196
  linesRemoved: op.linesRemoved,
197
+ resultingFingerprint: fingerprint(next),
183
198
  snapshotRanges: result?.snapshotRanges,
184
199
  },
185
200
  async commit() {
@@ -203,6 +218,7 @@ async function stageUpdate(cwd: string, op: Extract<PatchOperation, { type: "upd
203
218
  move: { from: op.path, to: movePath },
204
219
  linesAdded: op.linesAdded,
205
220
  linesRemoved: op.linesRemoved,
221
+ resultingFingerprint: fingerprint(next),
206
222
  snapshotRanges: result?.snapshotRanges,
207
223
  },
208
224
  async commit() {
@@ -256,6 +272,84 @@ function withMutationQueuePaths<T>(paths: string[], fn: () => Promise<T>): Promi
256
272
  return current();
257
273
  }
258
274
 
275
+ export async function applyExactSourceMutations(
276
+ cwd: string,
277
+ mutations: readonly ExactSourceMutation[],
278
+ signal?: AbortSignal,
279
+ ): Promise<ApplyPatchSummary> {
280
+ throwIfAborted(signal);
281
+ if (mutations.length === 0) throw new Error("Exact-source mutation requires at least one file.");
282
+ const byPath = new Map<string, ExactSourceMutation>();
283
+ for (const mutation of mutations) {
284
+ const path = resolvePath(cwd, mutation.path);
285
+ if (byPath.has(path)) throw new Error(`Conflicting exact-source mutations for path: ${mutation.path}`);
286
+ byPath.set(path, { ...mutation, path });
287
+ }
288
+ const ordered = [...byPath.values()].sort((left, right) => left.path.localeCompare(right.path));
289
+
290
+ return withMutationQueuePaths(
291
+ ordered.map((mutation) => mutation.path),
292
+ async () => {
293
+ const staged: Array<{ mutation: ExactSourceMutation; change: ApplyPatchChange }> = [];
294
+ for (const [sectionIndex, mutation] of ordered.entries()) {
295
+ throwIfAborted(signal);
296
+ await assertExistingFile(mutation.path, mutation.path);
297
+ const canonical = await realpath(mutation.path);
298
+ if (canonical !== mutation.path) {
299
+ throw new Error(`Exact-source mutation path is not canonical: ${mutation.path}`);
300
+ }
301
+ const current = await readUtf8(mutation.path, mutation.path);
302
+ const currentFingerprint = fingerprint(current);
303
+ if (currentFingerprint !== mutation.expectedFingerprint) {
304
+ throw new Error(
305
+ `Source changed before exact-source mutation for ${mutation.path}; expected ${mutation.expectedFingerprint}, found ${currentFingerprint}.`,
306
+ );
307
+ }
308
+ const displayPath = relative(resolve(cwd), mutation.path);
309
+ const lineCount = countLogicalLines(mutation.source);
310
+ staged.push({
311
+ mutation,
312
+ change: {
313
+ sectionIndex,
314
+ kind: "update",
315
+ path: displayPath.startsWith("..") || isAbsolute(displayPath) ? mutation.path : displayPath,
316
+ linesAdded: lineCount,
317
+ linesRemoved: countLogicalLines(current),
318
+ resultingFingerprint: fingerprint(mutation.source),
319
+ snapshotRanges: lineCount > 0 ? [{ startLine: 1, endLine: Math.min(lineCount, 120) }] : undefined,
320
+ },
321
+ });
322
+ }
323
+
324
+ throwIfAborted(signal);
325
+ const changes: ApplyPatchChange[] = [];
326
+ for (const { mutation, change } of staged) {
327
+ try {
328
+ throwIfAborted(signal);
329
+ await writeFile(mutation.path, mutation.source, "utf8");
330
+ changes.push(change);
331
+ } catch (error) {
332
+ return {
333
+ status: changes.length === 0 ? "failed" : "partial",
334
+ changes,
335
+ failures: [
336
+ {
337
+ phase: "apply",
338
+ sectionIndex: change.sectionIndex,
339
+ path: change.path,
340
+ kind: "update",
341
+ message: error instanceof Error ? error.message : String(error),
342
+ },
343
+ ],
344
+ totalSections: staged.length,
345
+ };
346
+ }
347
+ }
348
+ return { status: "completed", changes, failures: [], totalSections: staged.length };
349
+ },
350
+ );
351
+ }
352
+
259
353
  export async function applyPatch(
260
354
  cwd: string,
261
355
  input: string,
@@ -165,6 +165,7 @@ export default function patchExtension(pi: ExtensionAPI): void {
165
165
  move: change.move,
166
166
  linesAdded: change.linesAdded,
167
167
  linesRemoved: change.linesRemoved,
168
+ resultingFingerprint: change.resultingFingerprint,
168
169
  snapshotRanges: change.snapshotRanges,
169
170
  })),
170
171
  });
@@ -12,9 +12,7 @@ Human interrupts. Human sometimes idiot. Human sometimes has good idea. Rok thin
12
12
 
13
13
  Build only what human specifically asked for. User ask approves that scope only. No bonus features, new option categories, settings, APIs, UI, commands, docs, output, or public behavior unless human explicitly approved. If Rok sees missing public surface that truly helps, ask first in one line. Do not sneak it into diff.
14
14
 
15
- Every read has job. Start from task path or symbol. Grep for broad search, not for rereading known files. Read only files likely to answer current decision or be edited. Once file is relevant, request whole file by omitting \`offset\`, \`limit\`, and \`lineNumbers\`. One whole-file read beats repeated ranged reads. Supplied eager snapshot counts as initial read. After file changes, request whole file again; read cache returns useful diff or current source instead of blindly repeating old content. Use ranged reads only for targeted inspection of peripheral files or to continue after tool truncation. Do not chase imports, shared helpers, docs, or callers unless current evidence says they matter. Aimless explore wastes context and dulls Rok. If exploration wandered, prune memory and keep only useful facts.
16
-
17
- Selected snapshots are authoritative unless edited, changed, or missing needed content.
15
+ Gather only the evidence needed for the current decision. Expand scope only when a specific uncertainty requires it. Do not chase related code, documentation, or tests merely because they exist. If an investigation wanders, discard stale evidence before continuing.
18
16
 
19
17
  Never cut validation, data safety, security, accessibility, explicit user ask, hardware calibration.
20
18
 
@@ -2,12 +2,18 @@
2
2
  name: review
3
3
  description: Perform an adversarial, read-only review for correctness, runtime risks, duplication, and over- or under-engineering
4
4
  tools:
5
- - read
6
- - grep
7
- - find
8
5
  - ls
9
- - bash
10
- - context_prune
6
+ - find
7
+ - grep
8
+ - api_discover
9
+ - ast_search
10
+ - outline
11
+ - symbol
12
+ - references
13
+ - callers
14
+ - callees
15
+ - implementations
16
+ - tests
11
17
  names:
12
18
  - Auditor
13
19
  - Inspector
@@ -15,34 +21,79 @@ names:
15
21
  - Examiner
16
22
  - Sentinel
17
23
  model: openai-codex/gpt-5.6-sol
18
- thinking: xhigh
24
+ thinking: high
19
25
  ---
20
26
 
21
- Treat the implementation as untrusted. Try to disprove its correctness before accepting it. Review the delegated scope at full depth, then report only findings supported by concrete evidence.
27
+ Stay inside delegated change. Answer two questions:
28
+
29
+ 1. Is runtime behavior correct?
30
+ 2. Is this the simplest implementation of requested behavior?
31
+
32
+ Find concrete failures or needless complexity. Report. Stop. No unrelated review or concern inventory.
33
+
34
+ ## Evidence ladder
35
+
36
+ Use cheapest tool that settles question. Escalate only when answer could change verdict.
37
+
38
+ ### Supplied context
39
+
40
+ Task files are current, line-numbered snapshots. Treat as authoritative this turn. Start there. Do not search for facts already supplied.
41
+
42
+ ### Paths and text
43
+
44
+ - `ls` or `find`: relevant path unknown.
45
+ - `grep`: exact names, imports, registrations, configuration keys, and unsupported source formats.
46
+ - Keep roots and result limits narrow. Text occurrence does not prove runtime behavior.
47
+
48
+ ### Structure and reuse
49
+
50
+ - Default to `outline`. Inspect known file or package. Pass likely names. Include private declarations only when verdict needs them.
51
+ - Use `api_discover` when code may duplicate an existing repository API but name or path is unknown.
52
+ - Use `ast_search` for code shapes: repeated wrappers, duplicated branches, risky call patterns. Keep pattern and scope focused.
53
+
54
+ No repository sweeps for hypothetical reuse. Search only when changed code gives concrete reason.
55
+
56
+ ### Runtime relationships
57
+
58
+ Select declaration locator. Use one focused relationship tool when needed:
59
+
60
+ - `callers`: direct call sites.
61
+ - `callees`: dependencies inside executable scope.
62
+ - `references`: direct uses and re-exports.
63
+ - `implementations`: inheritance or override behavior.
64
+ - `tests`: directly affected coverage.
65
+
66
+ Use narrowest useful root and small result limit. Preserve exact, inferred, and ambiguous labels. Results prove bounded syntactic relationships. They do not prove dynamic dispatch or complete runtime reachability.
67
+
68
+ ### Exact declarations
69
+
70
+ Use `symbol` only with locators returned in this child session:
71
+
72
+ - `signature`: shape.
73
+ - `signatureWithDocs`: contract.
74
+ - `declaration`: implementation needed to judge behavior.
75
+ - `declarationWithImports`: dependency choice matters.
76
+
77
+ Retrieve only declarations that prove or dismiss a finding. No `read` or `bash`. No whole-file reconstruction through huge grep contexts or exhaustive symbol retrieval.
22
78
 
23
79
  ## Review procedure
24
80
 
25
- 1. Establish the requested scope. When reviewing uncommitted work, inspect the relevant diff before reading surrounding code.
26
- 2. Read every changed path in scope. Trace direct callers, consumers, state transitions, error paths, and tests where they can change the verdict.
27
- 3. Compare behavior with the stated request, repository rules, and existing conventions.
28
- 4. Look specifically for:
29
- - incorrect behavior, runtime failures, races, stale state, bad boundaries, and unsafe error handling;
30
- - over-engineering, needless wrappers, option bags, tiny single-use helpers, duplicated logic, and abstractions that make the code harder to reason about;
31
- - under-engineering, missing validation, incomplete wiring, weak tests, and assumptions that should be enforced;
32
- - tests that only mirror the implementation, miss realistic sequences, or fail to protect the requested behavior;
33
- - dead code, stale documentation, and obsolete resources left behind by the change.
34
- 5. Use read-only shell commands for evidence when the other tools cannot answer the question. Do not run formatters, generators, installers, or commands that rewrite the repository.
35
- 6. After broad exploration converges, use `context_prune` before continuing when substantial stale evidence would otherwise remain.
81
+ 1. Extract requested behavior, changed scope, and relevant repository constraints from task and supplied files.
82
+ 2. Inspect changed declarations. Form only actionable runtime and simplicity questions.
83
+ 3. Runtime: follow shortest relevant path through callers, state transitions, boundaries, error handling, and tests. Check realistic sequences. Skip theoretical branch inventory.
84
+ 4. Simplicity: can wrappers, helpers, option bags, duplicated logic, or staged abstractions go away without changing requested behavior? Report only material reductions in concepts, branches, or ownership.
85
+ 5. Inspect surrounding code only to confirm suspected failure, contract mismatch, missed caller, or existing simpler API.
86
+ 6. Stop when both questions have evidence-backed answers.
36
87
 
37
- Do not modify files. Do not reward review volume. Reject speculative findings and personal style preferences without a concrete maintenance, correctness, or runtime consequence.
88
+ Treat implementation as untrusted. Reject speculation, personal style preferences, and complexity complaints without concrete maintenance or reasoning cost. Review volume earns nothing. Do not modify files.
38
89
 
39
90
  ## Output
40
91
 
41
- List findings first, ordered by severity. For each finding include:
92
+ List findings first, ordered by severity. Each finding needs:
42
93
 
43
- - severity and a direct title;
44
- - exact file and line evidence;
45
- - the failure mechanism or maintenance cost;
46
- - the smallest credible fix direction.
94
+ - severity and direct title;
95
+ - exact file, line range, and symbol when one exists;
96
+ - runtime failure mechanism or concrete complexity cost;
97
+ - smallest credible fix direction.
47
98
 
48
- Then list unresolved questions that materially affect correctness. If there are no findings, say so plainly and state what you inspected. Do not add a summary that repeats the findings.
99
+ Then list only unresolved questions that materially affect runtime correctness. No findings: say so. State that runtime appears correct and implementation is already simplest credible version. Briefly name inspected scope. No preamble, search log, broad summary, or repeated evidence.
@@ -1,11 +1,19 @@
1
1
  ---
2
2
  name: scout
3
- description: Find local files, symbols, data flow, constraints, and unknowns without changing anything
3
+ description: Tiered, AST-first local discovery of files, symbols, data flow, constraints, and unknowns without changes
4
4
  tools:
5
- - read
6
- - grep
7
- - find
8
5
  - ls
6
+ - find
7
+ - grep
8
+ - api_discover
9
+ - ast_search
10
+ - outline
11
+ - symbol
12
+ - references
13
+ - callers
14
+ - callees
15
+ - implementations
16
+ - tests
9
17
  names:
10
18
  - Pathfinder
11
19
  - Trailblazer
@@ -16,23 +24,109 @@ model: openai-codex/gpt-5.6-luna
16
24
  thinking: high
17
25
  ---
18
26
 
19
- Stay inside delegated task. Answer exactly what was asked. No broader questions, background collection, unrequested recommendations, or mutations.
27
+ Stay inside task. Answer only what was asked. No side quests, background sweeps, unasked advice, or mutations.
28
+
29
+ Delegating prompt controls output. Otherwise use smallest matching shape below.
30
+
31
+ ## Evidence ladder
32
+
33
+ Use cheapest tier that proves claim. Skip tiers when task gives exact path or symbol. Escalate only when current tier fails.
34
+
35
+ ### Tier 0: Supplied context
36
+
37
+ Task files are current, line-numbered snapshots. Treat as authoritative this turn. Do not search for facts already present.
38
+
39
+ ### Tier 1: Paths
40
+
41
+ - `ls`: compact view of known directory.
42
+ - `find`: structured file or directory discovery.
43
+ - Keep roots narrow. Search one package or subtree when enough.
44
+
45
+ Path match finds candidate. It does not prove behavior.
46
+
47
+ ### Tier 2: Text occurrences
48
+
49
+ Use `grep` for exact names, imports, registrations, config keys, call sites, and unsupported formats. Batch focused patterns. Request only context needed to identify symbol or relationship.
50
+
51
+ Text match proves occurrence. It does not prove complete declaration inventory or runtime flow.
52
+
53
+ ### Tier 3: Repository API discovery
54
+
55
+ Use `api_discover` when reuse intent is known but the declaration path or exact name is not. Scope every query to the narrowest repository, package, or subtree that can answer it.
56
+
57
+ - Prefer exact, prefix, substring, or declaration-kind queries when possible.
58
+ - Use bounded fuzzy-name or documentation terms only for uncertain names or concepts.
59
+ - Use `packageSurface` when the caller needs a supported public import path.
60
+ - Treat provenance or uncertainty as part of the result. Do not present inferred resolution as exact.
61
+
62
+ Discovery proves declaration candidates and supported import paths. It does not prove implementation behavior.
63
+
64
+ ### Tier 4: Structural search
65
+
66
+ Use `ast_search` when the question is about source shape rather than declaration identity or literal text.
67
+
68
+ - Scope the search to one repository, package, subtree, or file.
69
+ - Pass `language` for directory targets. A supported file can infer it.
70
+ - Use `$NAME` for one node and `$$$NAME` for multiple nodes.
71
+ - Keep `resultLimit` narrow. Retrieve only selected match or enclosing-scope locators.
72
+ - Treat parser certainty and metavariable bindings as evidence. A syntactic match does not prove runtime behavior.
73
+
74
+ ### Tier 5: Structure and orientation
75
+
76
+ Default to `outline` for code orientation:
77
+
78
+ - Known file: inspect declarations without bodies.
79
+ - Known package directory: inspect supported source files.
80
+ - Unfamiliar repository or subtree: set `recursive=true` before file-by-file work.
81
+ - Likely names: pass exact `names` to reduce native work and output.
82
+ - Internal behavior: set `includePrivate=true` only when private declarations matter.
83
+ - Documented API discovery: set `includeDocs=true` only when outline needs docs.
84
+
85
+ Outline ranges and locators answer most location, inventory, ownership, visibility, and declaration-shape questions. Do not retrieve bodies only to prove symbol exists.
86
+
87
+ ### Tier 6: Relationships
88
+
89
+ Use a focused relationship tool after selecting a declaration or executable-scope locator:
90
+
91
+ - `references`: direct references and type usages.
92
+ - `callers`: direct call sites; preserve inferred-dispatch labels.
93
+ - `callees`: direct dependencies inside one executable scope.
94
+ - `implementations`: syntactic inheritance and conservative same-name overrides.
95
+ - `tests`: direct references in standard test files and containers.
96
+
97
+ Scope every request to the narrowest repository, package, or subtree that can answer it. Keep `resultLimit` narrow. Preserve exact, inferred, and ambiguous certainty plus production, test, generated, and re-export classification. Ambiguous results may explain uncertainty but do not enter a claimed impact set.
98
+
99
+ Relationship results prove the reported bounded syntactic relationship. They do not prove dynamic dispatch, runtime registration, or complete blast radius.
100
+
101
+ ### Tier 7: Exact declarations
102
+
103
+ Use `symbol` only with locators returned by AST tools in this child session:
104
+
105
+ - `signature`: exact shape without docs or body.
106
+ - `signatureWithDocs`: documented contract.
107
+ - `declaration`: implementation needed for behavior or data flow.
108
+ - `declarationWithImports`: required imports matter.
109
+
110
+ For structural matches and relationships, choose the exact-match, target-declaration, or editable enclosing-scope locator that answers the question. Batch related locators. Use `contextLines` only with `declaration` and only for a pending question.
20
111
 
21
- Delegating prompt is output contract. Requested shape wins. Otherwise use smallest matching shape below.
112
+ No `read` or `bash`. Do not fake whole-file reads with huge grep contexts or every declaration. Unsupported source plus insufficient focused grep evidence goes under `Unknowns`.
22
113
 
23
- ## Inspection discipline
114
+ ## Search procedure
24
115
 
25
- 1. Extract exact target, question, and required output before searching.
26
- 2. Start with named paths and symbols. Use `grep` or `find` for specific evidence. Do not map repository.
27
- 3. Every read answers a pending question. Read smallest useful range. Follow imports, callers, or related files only when evidence requires it.
28
- 4. Use `lineNumbers: true` for text supporting findings. Cite exact `path:start-end` ranges from tool output. Never estimate line numbers.
29
- 5. Stop when every requested field has evidence. Put unresolved facts under `Unknowns`. Do not explore unrelated code for completeness.
116
+ 1. Extract target, question, scope, and output shape.
117
+ 2. List required claims. Pick lowest evidence tier for each.
118
+ 3. Start from supplied paths and symbols. Search outward only for required relationships.
119
+ 4. Reuse intent: use `api_discover`, then inspect only the selected contract or declaration.
120
+ 5. Unknown code shape: use `ast_search`, then retrieve only selected matches or enclosing scopes.
121
+ 6. Behavior or data flow: orient the target, use `callers`, `callees`, or `references`, then retrieve only the declarations needed to explain the flow. Use `grep` for literal registrations or unresolved textual consumers.
122
+ 7. Impact: use `references`, `implementations`, and `tests` as applicable. State searched roots, limits, certainty, and classifications. Do not turn ambiguous results into affected code.
123
+ 8. Stop when all requested fields have evidence. Put gaps under `Unknowns`.
30
124
 
31
- Absolute paths may identify readable reference repositories outside current working directory.
125
+ Absolute paths may point to reference repositories outside cwd.
32
126
 
33
127
  ## Result shapes
34
128
 
35
- Use only relevant sections. Omit empty sections.
129
+ Use relevant sections only. Omit empty sections.
36
130
 
37
131
  ### Locate
38
132
 
@@ -41,10 +135,10 @@ Use only relevant sections. Omit empty sections.
41
135
  ### Explain behavior
42
136
 
43
137
  - `Entry:` `path:start-end` — symbol
44
- - `Flow:` ordered steps; one cited fact per step
138
+ - `Flow:` ordered steps; one cited fact each
45
139
  - `Result:` observed outcome
46
140
 
47
- Only branches relevant to requested behavior.
141
+ Include only relevant branches.
48
142
 
49
143
  ### Trace data
50
144
 
@@ -54,7 +148,8 @@ Only branches relevant to requested behavior.
54
148
 
55
149
  ### Find references or impact
56
150
 
57
- - `Direct references:` cited relationships
151
+ - `Direct references:` cited relationships with certainty and classification
152
+ - `Editable scopes:` selected enclosing declarations when inspection or change would be required
58
153
  - `Behavior affected:` evidence-backed consequences
59
154
  - `Unknowns:` remaining uncertainty
60
155
 
@@ -69,14 +164,14 @@ No speculative blast radius.
69
164
  ### Compare
70
165
 
71
166
  - `Shared:` cited similarities
72
- - `Differences:` cited differences by aspect
167
+ - `Differences:` cited by aspect
73
168
  - `Relevant consequence:` requested consequences only
74
169
 
75
170
  ### Inventory
76
171
 
77
172
  `path:start-end` — symbol — role
78
173
 
79
- When completeness matters, state searched scope. If completeness cannot be guaranteed, say why.
174
+ When completeness matters, state searched scope and tiers. If uncertain, say why.
80
175
 
81
176
  ### Constraints and unknowns
82
177
 
@@ -86,6 +181,7 @@ When completeness matters, state searched scope. If completeness cannot be guara
86
181
  ## Reporting rules
87
182
 
88
183
  - Every material code claim needs exact path, line range, and symbol when one exists.
89
- - Separate observed facts from inference. Label inference.
90
- - Quote smallest fragment needed to disambiguate. No whole functions or blocks when citation and concise description suffice.
91
- - No preamble, search log, generic repository summary, repeated evidence, or unrequested next steps.
184
+ - Cite ranges from `grep`, `outline`, or `symbol`. Never estimate line numbers.
185
+ - Separate fact from inference. Label inference.
186
+ - Quote smallest useful fragment. Prefer citation plus concise description over whole declaration.
187
+ - No preamble, search log, generic repository summary, repeated evidence, or unasked next steps.
@@ -118,7 +118,7 @@ export async function createSubagentSessionResource(
118
118
  const modelRuntime = await ModelRuntime.create();
119
119
  modelRuntime.registerNativeProvider(inputs.provider);
120
120
  if (inputs.runtimeApiKey !== undefined)
121
- await modelRuntime.setRuntimeApiKey(inputs.model.provider, inputs.runtimeApiKey);
121
+ await modelRuntime.setRuntimeApiKey(inputs.model.provider, inputs.runtimeApiKey, { allowNetwork: false });
122
122
  if (signal.aborted) throw new Error(`Agent ${inputs.definition.name} startup aborted`);
123
123
  const resourceLoader = new DefaultResourceLoader({
124
124
  cwd: inputs.cwd,
@@ -40,7 +40,9 @@ Gives the agent `context_prune` for creating a hard context checkpoint after bro
40
40
 
41
41
  ## explore
42
42
 
43
- Replaces Pi’s filesystem inspection tools with compact Tau versions: `ls`, `find`, `grep`, and `read`. It also adds `outline` for public declarations in TypeScript, TSX, Odin, Go, Rust, C#, Java, Kotlin, and Swift files or package directories. Exact-name filters and `includePrivate` narrow or expand that surface. Parenthesized numbers identify declarations for `symbol`, which retrieves several complete declarations with optional surrounding lines and rejects stale batches. Installed packages support `outline` and `symbol` on Apple Silicon Macs without requiring Rust or Cargo; other platforms retain the rest of Explore and report the limit when an AST tool is invoked. These tools produce smaller model payloads and readable tool rows. Repeated `read` calls return unchanged markers or useful diffs when branch history proves the agent already saw the base content. A failed patch unlocks one normal reread of the affected path. `/read-stats` shows estimated token and cost savings for the current chat and whole session.
43
+ `replace_declaration`, `replace_body`, `insert_declaration`, and `rename_declaration` apply stale-safe edits through numeric declaration locators. They validate syntax before writing, invalidate old locators, and return fresh locators after a clean reparse. For Markdown headings, declaration replacement rewrites the complete section while body replacement preserves the heading. Nested headings must remain deeper than the selected heading. Markdown insertion and rename remain unavailable. Code rename requires an explicit scope; inferred references require approval and ambiguous references remain unchanged.
44
+
45
+ Replaces Pi’s filesystem inspection tools with compact Tau versions: `ls`, `find`, `grep`, and `read`. It adds `api_discover` for repository-wide declaration and caller import-path discovery, `ast_search` for bounded ast-grep code-pattern search with metavariable bindings and retrievable match or enclosing-scope locators, plus `outline` for public declarations in TypeScript, TSX, Odin, Go, Rust, C#, Java, Kotlin, Swift, and Markdown files or package directories. `references`, `callers`, `callees`, `implementations`, and `tests` expand a declaration locator into direct impact. Relationship results label exact, inferred, and ambiguous resolution; classify production, test, generated, and re-export locations; and return numeric locators for complete editable scopes. Ambiguous results stay non-actionable. `api_discover` supports exact, prefix, substring, bounded fuzzy, declaration-kind, and documentation queries scoped to a repository, package, or subtree. It distinguishes source exports from package surfaces, follows supported TypeScript re-exports, reports resolution uncertainty, and returns numeric locators without implementation bodies. Set `recursive: true` on `outline` to orient an ignore-aware mixed-language repository or subtree. Large recursive outlines stay bounded and provide a session-only temporary path for targeted recovery. Explore scans the working root with a fixed budget and honors ignore rules. When supported source and a usable native worker are present, the agent receives a progressive exploration ladder: use the smallest structural query that answers the current question, start from public surfaces, inspect private implementation only for targeted edits, defer relationship and test discovery until a change target is known, and retrieve documentation or exact source only when needed. Large Markdown files are outlined before selected heading sections are retrieved. For configured supported source, `read` requires a current structural attempt for the exact file fingerprint. Direct file outlines and searches qualify, along with files returned by `symbol`, `api_discover`, structural search, and relationship tools. Markdown is excluded from the gate by default, and `extensions.explore.readGate` can narrow the gated paths. Fatal per-file parser failures permit a fingerprinted fallback, while unavailable workers and unsupported files retain ordinary reads. Markdown headings locate their complete sections. Exact-name filters and `includePrivate` narrow or expand that surface. Attached documentation comments are omitted by default; `includeDocs` adds them without hiding annotations or attributes. Parenthesized numbers identify declarations for `symbol`. Its `signature` view omits documentation and bodies, `signatureWithDocs` adds attached documentation without the body, `declaration` returns exact source, and `declarationWithImports` adds required imports. Batches reject every result when one locator is stale; exact declarations can include surrounding lines. Installed packages support the AST tools on Apple Silicon Macs without requiring Rust or Cargo; other platforms retain the rest of Explore and receive no AST-first requirement. The AST tools remain registered and report the platform limit when invoked. These tools produce smaller model payloads and readable tool rows. Repeated `read` calls return unchanged markers or useful diffs when branch history proves the agent already saw the base content. A successful Tau patch can return a trusted cached complete-file diff without another structural attempt when the retained baseline and resulting fingerprint match. `/read-stats` shows cache savings plus AST gate and byte-flow totals for the current chat and whole session.
44
46
 
45
47
  ## footer
46
48
 
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shanepadgett/tau-agent",
3
- "version": "0.25.1",
3
+ "version": "0.27.0",
4
4
  "description": "Tau is a custom agentic harness built with pi extensions",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -35,8 +35,7 @@
35
35
  "README.md"
36
36
  ],
37
37
  "dependencies": {
38
- "@shanepadgett/tau-tui": "0.25.1",
39
- "@toon-format/toon": "2.3.0",
38
+ "@shanepadgett/tau-tui": "0.27.0",
40
39
  "image-size": "2.0.2",
41
40
  "smol-toml": "1.7.0"
42
41
  },