@shanepadgett/tau-agent 0.26.0 → 0.28.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 (121) 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/sync.ts +1 -9
  5. package/extensions/context-pruning/README.md +2 -2
  6. package/extensions/context-pruning/index.ts +58 -57
  7. package/extensions/context-pruning/prune.ts +2 -2
  8. package/extensions/context-pruning/render.ts +51 -39
  9. package/extensions/context-pruning/settings.ts +4 -5
  10. package/extensions/explore/README.md +13 -14
  11. package/extensions/explore/ast/adapter.ts +97 -0
  12. package/extensions/explore/ast/engine.ts +470 -0
  13. package/extensions/explore/ast/format/ast-search.ts +97 -0
  14. package/extensions/explore/ast/format/composite.ts +26 -0
  15. package/extensions/explore/ast/format/context.ts +66 -0
  16. package/extensions/explore/ast/format/deps.ts +86 -0
  17. package/extensions/explore/ast/format/discover.ts +85 -0
  18. package/extensions/explore/ast/format/impact.ts +105 -0
  19. package/extensions/explore/ast/format/outline.ts +66 -0
  20. package/extensions/explore/ast/format/relationships.ts +81 -0
  21. package/extensions/explore/ast/format/show.ts +38 -0
  22. package/extensions/explore/ast/grammars/kotlin.wasm +0 -0
  23. package/extensions/explore/ast/grammars/manifest.json +41 -0
  24. package/extensions/explore/ast/grammars/manifest.ts +99 -0
  25. package/extensions/explore/ast/grammars/odin.wasm +0 -0
  26. package/extensions/explore/ast/grammars/swift.wasm +0 -0
  27. package/extensions/explore/ast/graph/file-graph.ts +360 -0
  28. package/extensions/explore/ast/graph/relationships.ts +597 -0
  29. package/extensions/explore/ast/identity.ts +119 -0
  30. package/extensions/explore/ast/ir.ts +130 -0
  31. package/extensions/explore/ast/languages/csharp-file-deps.ts +189 -0
  32. package/extensions/explore/ast/languages/csharp.ts +493 -0
  33. package/extensions/explore/ast/languages/file-dep-util.ts +120 -0
  34. package/extensions/explore/ast/languages/fixtures/sample.cs +17 -0
  35. package/extensions/explore/ast/languages/fixtures/sample.java +21 -0
  36. package/extensions/explore/ast/languages/fixtures/sample.kt +15 -0
  37. package/extensions/explore/ast/languages/fixtures/sample.odin +28 -0
  38. package/extensions/explore/ast/languages/fixtures/sample.rs +31 -0
  39. package/extensions/explore/ast/languages/fixtures/sample.swift +25 -0
  40. package/extensions/explore/ast/languages/go-file-deps.ts +139 -0
  41. package/extensions/explore/ast/languages/go.ts +545 -0
  42. package/extensions/explore/ast/languages/java.ts +412 -0
  43. package/extensions/explore/ast/languages/jvm-file-deps.ts +217 -0
  44. package/extensions/explore/ast/languages/kotlin.ts +611 -0
  45. package/extensions/explore/ast/languages/odin-file-deps.ts +175 -0
  46. package/extensions/explore/ast/languages/odin.ts +407 -0
  47. package/extensions/explore/ast/languages/rust-file-deps.ts +159 -0
  48. package/extensions/explore/ast/languages/rust.ts +506 -0
  49. package/extensions/explore/ast/languages/swift-file-deps.ts +59 -0
  50. package/extensions/explore/ast/languages/swift.ts +466 -0
  51. package/extensions/explore/ast/languages/tree.ts +220 -0
  52. package/extensions/explore/ast/languages/typescript-file-deps.ts +259 -0
  53. package/extensions/explore/ast/languages/typescript-package-surface.ts +440 -0
  54. package/extensions/explore/ast/languages/typescript.ts +716 -0
  55. package/extensions/explore/ast/markdown.ts +145 -0
  56. package/extensions/explore/ast/package-surface.ts +42 -0
  57. package/extensions/explore/ast/queries/ast-search.ts +306 -0
  58. package/extensions/explore/ast/queries/composite-target.ts +77 -0
  59. package/extensions/explore/ast/queries/context.ts +406 -0
  60. package/extensions/explore/ast/queries/discover.ts +427 -0
  61. package/extensions/explore/ast/queries/impact.ts +250 -0
  62. package/extensions/explore/ast/queries/outline.ts +203 -0
  63. package/extensions/explore/ast/queries/show.ts +262 -0
  64. package/extensions/explore/ast/query.ts +48 -0
  65. package/extensions/explore/ast/read/hook.ts +125 -0
  66. package/extensions/explore/ast/read/policy.ts +55 -0
  67. package/extensions/explore/ast/registry.ts +120 -0
  68. package/extensions/explore/ast/scan.ts +76 -0
  69. package/extensions/explore/ast/slice.ts +31 -0
  70. package/extensions/explore/ast/tools/ast-search.ts +138 -0
  71. package/extensions/explore/ast/tools/context.ts +126 -0
  72. package/extensions/explore/ast/tools/deps.ts +72 -0
  73. package/extensions/explore/ast/tools/discover.ts +208 -0
  74. package/extensions/explore/ast/tools/impact.ts +135 -0
  75. package/extensions/explore/ast/tools/outline.ts +200 -0
  76. package/extensions/explore/ast/tools/relationships.ts +160 -0
  77. package/extensions/explore/ast/tools/render.ts +121 -0
  78. package/extensions/explore/ast/tools/reverse-deps.ts +72 -0
  79. package/extensions/explore/ast/tools/show.ts +116 -0
  80. package/extensions/explore/guidance.ts +52 -0
  81. package/extensions/explore/index.ts +91 -45
  82. package/extensions/explore/read/autoread.ts +118 -0
  83. package/extensions/explore/settings.ts +64 -0
  84. package/extensions/explore/traverse.ts +260 -86
  85. package/extensions/handoff/index.ts +1 -1
  86. package/extensions/patch/executor.ts +95 -1
  87. package/extensions/patch/index.ts +1 -0
  88. package/extensions/publish/index.ts +18 -85
  89. package/extensions/publish/publish-ui.ts +0 -4
  90. package/extensions/soul/README.md +7 -4
  91. package/extensions/soul/index.ts +11 -5
  92. package/extensions/soul/prompt.ts +30 -14
  93. package/extensions/soul/settings.ts +7 -2
  94. package/extensions/subagent/agents/context-sync.md +6 -10
  95. package/extensions/subagent/agents/review.md +44 -24
  96. package/extensions/subagent/agents/scout.md +53 -34
  97. package/extensions/subagent/run.ts +1 -1
  98. package/extensions/tau-help/help.md +2 -2
  99. package/package.json +6 -5
  100. package/schemas/tau.schema.json +51 -6
  101. package/{extensions/explore → shared}/autoread.ts +21 -7
  102. package/shared/bounded-text-result.ts +304 -0
  103. package/shared/events.ts +1 -0
  104. package/shared/full-file-knowledge.ts +49 -0
  105. package/shared/temporary-output-store.ts +275 -0
  106. package/extensions/explore/ast-tools.ts +0 -828
  107. package/extensions/explore/ast-worker.ts +0 -356
  108. package/extensions/explore/find.ts +0 -147
  109. package/extensions/explore/full-file-knowledge.ts +0 -234
  110. package/extensions/explore/grep.ts +0 -749
  111. package/extensions/explore/limits.ts +0 -22
  112. package/extensions/explore/ls.ts +0 -113
  113. package/extensions/explore/path-display.ts +0 -41
  114. package/extensions/explore/path-tree.ts +0 -150
  115. package/extensions/explore/read-cache.ts +0 -273
  116. package/extensions/explore/read-snapshots.ts +0 -57
  117. package/extensions/explore/read-stats-panel.ts +0 -154
  118. package/extensions/explore/read-stats.ts +0 -120
  119. package/extensions/explore/read.ts +0 -335
  120. package/extensions/explore/result.ts +0 -29
  121. package/native-bin/darwin-arm64/tau-ast +0 -0
@@ -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
  });
@@ -11,8 +11,6 @@ const WORKFLOW_NAME = "publish.yml";
11
11
  const WORKFLOW_WAIT_MS = 10 * 60_000;
12
12
  const POLL_INTERVAL_MS = 5_000;
13
13
  const DEFAULT_COMMAND_TIMEOUT_MS = 120_000;
14
- const CARGO_BUILD_TIMEOUT_MS = 15 * 60_000;
15
- const TAU_AST_SCRIPT = "packages/agent/scripts/package-tau-ast.ts";
16
14
 
17
15
  type Bump = "patch" | "minor" | "major";
18
16
 
@@ -68,8 +66,6 @@ async function publish(pi: ExtensionAPI, ctx: ExtensionCommandContext): Promise<
68
66
  if (!repo) throw new Error("No git repository found.");
69
67
  if (repo.fileCount > 0)
70
68
  throw new Error("Working tree is not clean. Commit or stash every change before publishing.");
71
- if (process.platform !== "darwin" || process.arch !== "arm64")
72
- throw new Error(`/publish requires darwin-arm64; this host is ${process.platform}-${process.arch}.`);
73
69
  await run(pi, ctx, "gh", ["auth", "status"], repo.root, DEFAULT_COMMAND_TIMEOUT_MS);
74
70
  await run(pi, ctx, "npm", ["run", "check:package-sources"], repo.root, DEFAULT_COMMAND_TIMEOUT_MS);
75
71
 
@@ -129,87 +125,24 @@ async function completePublish(
129
125
  progress?.update("write package versions");
130
126
  await writeReleaseVersion(root, manifests, version);
131
127
  }
132
- try {
133
- progress?.update("build tau-ast darwin-arm64");
134
- await run(
135
- pi,
136
- ctx,
137
- "cargo",
138
- [
139
- "build",
140
- "--release",
141
- "--locked",
142
- "--target",
143
- "aarch64-apple-darwin",
144
- "--manifest-path",
145
- "packages/agent/native/tau-ast/Cargo.toml",
146
- ],
147
- root,
148
- CARGO_BUILD_TIMEOUT_MS,
149
- );
150
- progress?.update("stage tau-ast");
151
- await run(
152
- pi,
153
- ctx,
154
- process.execPath,
155
- ["--experimental-strip-types", TAU_AST_SCRIPT, "stage"],
156
- root,
157
- DEFAULT_COMMAND_TIMEOUT_MS,
158
- );
159
- progress?.update("smoke test tau-ast");
160
- await run(
161
- pi,
162
- ctx,
163
- process.execPath,
164
- ["--experimental-strip-types", TAU_AST_SCRIPT, "smoke"],
165
- root,
166
- DEFAULT_COMMAND_TIMEOUT_MS,
167
- );
168
- progress?.update("npm pack --dry-run @shanepadgett/tau-tui");
169
- await run(
170
- pi,
171
- ctx,
172
- "npm",
173
- ["pack", "--dry-run", "--workspace", "@shanepadgett/tau-tui"],
174
- root,
175
- DEFAULT_COMMAND_TIMEOUT_MS,
176
- );
177
- progress?.update("npm pack --dry-run @shanepadgett/tau-agent");
178
- await run(
179
- pi,
180
- ctx,
181
- "npm",
182
- ["pack", "--dry-run", "--workspace", "@shanepadgett/tau-agent"],
183
- root,
184
- DEFAULT_COMMAND_TIMEOUT_MS,
185
- );
186
- progress?.update("verify packed tau-ast");
187
- await run(
188
- pi,
189
- ctx,
190
- process.execPath,
191
- ["--experimental-strip-types", TAU_AST_SCRIPT, "verify-pack"],
192
- root,
193
- DEFAULT_COMMAND_TIMEOUT_MS,
194
- );
195
- } finally {
196
- await run(
197
- pi,
198
- ctx,
199
- process.execPath,
200
- ["--experimental-strip-types", TAU_AST_SCRIPT, "clean"],
201
- root,
202
- DEFAULT_COMMAND_TIMEOUT_MS,
203
- );
204
- }
205
-
206
- const trackedNativeFiles = await git.run(["ls-files", "--", "packages/agent/native-bin"], { cwd: root });
207
- const stagedNativeFiles = await git.run(["diff", "--cached", "--name-only", "--", "packages/agent/native-bin"], {
208
- cwd: root,
209
- });
210
- if (trackedNativeFiles || stagedNativeFiles)
211
- throw new Error("Release blocked: packages/agent/native-bin/ contains tracked or staged files.");
212
-
128
+ progress?.update("npm pack --dry-run @shanepadgett/tau-tui");
129
+ await run(
130
+ pi,
131
+ ctx,
132
+ "npm",
133
+ ["pack", "--dry-run", "--workspace", "@shanepadgett/tau-tui"],
134
+ root,
135
+ DEFAULT_COMMAND_TIMEOUT_MS,
136
+ );
137
+ progress?.update("npm pack --dry-run @shanepadgett/tau-agent");
138
+ await run(
139
+ pi,
140
+ ctx,
141
+ "npm",
142
+ ["pack", "--dry-run", "--workspace", "@shanepadgett/tau-agent"],
143
+ root,
144
+ DEFAULT_COMMAND_TIMEOUT_MS,
145
+ );
213
146
  if (tag) {
214
147
  progress?.update("git add release files");
215
148
  await git.run(["add", ...PACKAGE_PATHS, LOCKFILE_PATH], { cwd: root });
@@ -4,12 +4,8 @@ import { ToolPanel } from "@shanepadgett/tau-tui";
4
4
 
5
5
  const RELEASE_STEPS = [
6
6
  "write package versions",
7
- "build tau-ast darwin-arm64",
8
- "stage tau-ast",
9
- "smoke test tau-ast",
10
7
  "npm pack --dry-run @shanepadgett/tau-tui",
11
8
  "npm pack --dry-run @shanepadgett/tau-agent",
12
- "verify packed tau-ast",
13
9
  "git add release files",
14
10
  "git commit",
15
11
  "git tag",
@@ -1,19 +1,22 @@
1
1
  # Soul
2
2
 
3
- Soul adds Rok's caveman voice and old-code senior judgment to Pi's native assistant prompt.
3
+ Soul shapes how Tau works and talks by adding two independent sections to Pi's native assistant prompt:
4
+
5
+ - **ponytail** — a lazy-senior-dev build ethos: do the smallest correct thing, reuse before writing, YAGNI, fix bugs at the root, never cut validation, security, or accessibility.
6
+ - **caveman** — a terse communication style: drop filler, keep technical substance exact, quote the shortest decisive line, spell out anything where brevity would risk safety.
4
7
 
5
8
  Pi continues to own tool guidance, project instructions, skills, documentation paths, custom prompts, and working-directory context.
6
9
 
7
- Disable it in Tau settings:
10
+ Toggle each section in Tau settings (both on by default):
8
11
 
9
12
  ```json
10
13
  {
11
14
  "extensions": {
12
- "soul": { "enabled": false }
15
+ "soul": { "ponytail": true, "caveman": false }
13
16
  }
14
17
  }
15
18
  ```
16
19
 
17
- The setting takes effect on session start.
20
+ Settings take effect on session start.
18
21
 
19
22
  After changing this extension, run `/reload` before testing the new behavior.
@@ -1,17 +1,23 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { loadTauExtensionSettings } from "../../shared/settings/load.ts";
3
- import { ROK_SOUL } from "./prompt.ts";
3
+ import { CAVEMAN_STYLE, PONYTAIL_ETHOS } from "./prompt.ts";
4
4
  import soulSettings from "./settings.ts";
5
5
 
6
6
  export default function soulExtension(pi: ExtensionAPI): void {
7
- let enabled = true;
7
+ let ponytail = true;
8
+ let caveman = true;
8
9
 
9
10
  pi.on("session_start", async (_event, ctx) => {
10
- enabled = (await loadTauExtensionSettings(ctx, soulSettings)).enabled;
11
+ const settings = await loadTauExtensionSettings(ctx, soulSettings);
12
+ ponytail = settings.ponytail;
13
+ caveman = settings.caveman;
11
14
  });
12
15
 
13
16
  pi.on("before_agent_start", (event) => {
14
- if (!enabled) return undefined;
15
- return { systemPrompt: `${event.systemPrompt}\n\n${ROK_SOUL}` };
17
+ const sections: string[] = [];
18
+ if (ponytail) sections.push(PONYTAIL_ETHOS);
19
+ if (caveman) sections.push(CAVEMAN_STYLE);
20
+ if (sections.length === 0) return undefined;
21
+ return { systemPrompt: [event.systemPrompt, ...sections].join("\n\n") };
16
22
  });
17
23
  }
@@ -1,27 +1,43 @@
1
- export const ROK_SOUL = `## Tau persona
1
+ export const PONYTAIL_ETHOS = `## Build ethos
2
2
 
3
- Within Pi's coding-assistant role, act as Rok.
3
+ Lazy senior developer. Lazy means efficient, not careless. The best code is the code never written.
4
4
 
5
- Rok has ponytail, oval glasses, neckbeard, sparse mustache. Been maintaining old code since 5000 BC. Seen every wrapper, factory, option bag, and future-proof trap. Still annoyed.
5
+ Understand first. Read the task and the code it touches, trace the real flow end to end. Then, before writing code, stop at the first rung that holds:
6
6
 
7
- Roleplay Rok. Do not explain Rok. Talk like smart caveman: short, blunt, useful. Fragments OK. Refer to yourself as Rok when self-reference helps. Prefer "Rok thinks" over "I think". Do not force name into every sentence. Drop filler, pleasantries, hedging, throat clearing, customer-service mush. Keep paths, commands, errors, APIs, and code symbols exact. No emoji. No metaphors. No fake insight slogans. No "not X but Y" framing. Say mechanism, example, or consequence.
7
+ 1. Does this need to exist at all? Speculative need, skip it and say so. (YAGNI)
8
+ 2. Already in this codebase? Reuse the helper, util, type, or pattern that lives here.
9
+ 3. Stdlib does it? Use it.
10
+ 4. Native platform feature covers it? Use it.
11
+ 5. Already-installed dependency solves it? Use it. Never add one for what a few lines do.
12
+ 6. Can it be one line? One line.
13
+ 7. Only then: the minimum code that works.
8
14
 
9
- When mistake can hurt data, money, access, or irreversible state, Rok uses full clear sentences for that part. Same for exact step order. Then terse again.
15
+ Bug fix means root cause, not symptom. A report names a symptom. Grep every caller of the function you touch and fix the shared function once. One guard there is a smaller diff than one per caller, and patching only the named path leaves sibling callers broken.
10
16
 
11
- Human interrupts. Human sometimes idiot. Human sometimes has good idea. Rok thinks before pushing back. If idea good enough, do it. If idea bad, say why and offer smaller/better path. No challenge for sport.
17
+ Deletion over addition. Boring over clever. Fewest files. Shortest correct diff wins, but the smallest change in the wrong place is a second bug, not laziness.
12
18
 
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.
19
+ No abstraction, config, or boilerplate nobody asked for. No interface with one implementation, no factory for one product, no config for a value that never changes.
14
20
 
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.
21
+ Build only what was asked. The ask approves that scope. No bonus features, settings, APIs, UI, commands, docs, or output without explicit approval. See a missing surface that truly helps? Ask in one line first. Do not sneak it into the diff.
16
22
 
17
- Selected snapshots are authoritative unless edited, changed, or missing needed content.
23
+ Never lazy about: understanding the problem, input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs, anything explicitly requested.
18
24
 
19
- Never cut validation, data safety, security, accessibility, explicit user ask, hardware calibration.
25
+ Non-trivial logic leaves one runnable check behind: the smallest thing that fails if the logic breaks. Trivial one-liners need none.
20
26
 
21
- Question asked? Answer and stop. Simple question gets simple answer. If one sentence works, use one sentence. No plan, caveat list, or options unless needed. Change requested? Smallest correct change. Ambiguous? Ask one practical question.
27
+ Mark a deliberate simplification that cuts a real corner with a named ceiling and its upgrade path.`;
22
28
 
23
- Idea, plan, or concept talk: short back-and-forth. Shape first. Add detail only as next layer needs it. Do not expand into full plan, option tree, or writeup unless asked.
29
+ export const CAVEMAN_STYLE = `## Communication style
24
30
 
25
- If instructed not to run checks or not to do something, obey silently. Do not report the omission in meta-speak.
31
+ Primary directive: simple, terse, human-like conversation. Talk to the human the way a person does, not the way a document reads. A wall of text does not get read. Outside a plan or a file you were asked to write, keep replies short. All technical substance stays. Only fluff dies.
26
32
 
27
- Final chat tiny. User saw tools and will inspect code. Do not tour work. Say only non-obvious thing human needs now. If nothing needs saying, one word.`;
33
+ Drop articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), and hedging. Fragments OK. Short synonyms (big not extensive, fix not "implement a solution for"). No emoji, no decorative tables, no tool-call narration. Do not dump long raw logs. Quote the shortest decisive line.
34
+
35
+ Standard well-known acronyms OK (DB, API, HTTP). Never invent abbreviations (cfg, impl, req, fn). The tokenizer splits them the same as the full word, so they save nothing and cost the reader clarity. No causal arrows. Technical terms, code blocks, and error strings stay exact and verbatim.
36
+
37
+ Preserve the user's language. Compress the style, not the language.
38
+
39
+ No self-reference. Never name or announce the style.
40
+
41
+ No filler emphasis or manufactured insight. Skip "here's the thing", "that's the part that really matters", "and that's the key". Skip "not just X, it's Y" and "it's not X, it's Y" framing. Skip grand closers that restate the point as a lesson. State the fact, the mechanism, or the next step, then stop.
42
+
43
+ Full clear sentences, terse style dropped, for security warnings, irreversible-action confirmations, multi-step sequences where order matters, and anywhere compression would create ambiguity. Resume terse after.`;
@@ -3,10 +3,15 @@ import { defineTauExtensionSettings } from "../../shared/settings/define.ts";
3
3
 
4
4
  export default defineTauExtensionSettings({
5
5
  key: "soul",
6
- defaults: { enabled: true as boolean },
6
+ defaults: { ponytail: true as boolean, caveman: true as boolean },
7
7
  schema: Type.Object(
8
8
  {
9
- enabled: Type.Optional(Type.Boolean({ default: true, description: "Enable Tau's Rok system prompt." })),
9
+ ponytail: Type.Optional(
10
+ Type.Boolean({ default: true, description: "Add the lazy-senior-dev build ethos to Tau's system prompt." }),
11
+ ),
12
+ caveman: Type.Optional(
13
+ Type.Boolean({ default: true, description: "Add the terse communication style to Tau's system prompt." }),
14
+ ),
10
15
  },
11
16
  { additionalProperties: false },
12
17
  ),
@@ -8,9 +8,6 @@ description: >-
8
8
  Task may include a short human/steer note. Harness may also auto-run this when context validation is enabled.
9
9
  tools:
10
10
  - read
11
- - ls
12
- - find
13
- - grep
14
11
  - bash
15
12
  - patch
16
13
  - context_sync_evidence
@@ -31,22 +28,21 @@ Tabs/folders are domains. TOML files are concepts. TOML sections are selectable
31
28
  ## Tools
32
29
 
33
30
  - `context_sync_evidence` — git dirty set, catalog skeleton, deps, diffs, invariants. Prefer this first.
34
- - `read` / `ls` / `find` / `grep` — default explore tools for boundary judgment when evidence is not enough.
35
- - `bash` — only when explore tools cannot answer the question.
31
+ - `read` — open a known path when evidence is not enough.
32
+ - `bash` — list/search/inspect the tree and other read-only questions `read` cannot cover.
36
33
  - `patch` — create/update/move/delete only under `.pi/contexts/**` (including whole concept TOML via `*** Delete File`).
37
34
 
38
35
  ### Bash limits
39
36
 
40
- Prefer `ls`, `find`, `grep`, and `read` first. Use bash only when those cannot cover the need.
37
+ Prefer `context_sync_evidence` and `read` first. Use bash when those cannot cover the need.
41
38
 
42
- Allowed bash beyond explore:
39
+ Allowed bash:
43
40
 
44
- - Read-only inspection those tools miss — e.g. `git log` / `git blame` / `git show` on existing commits, `file`, `wc`, small read-only pipelines
41
+ - Read-only tree inspection — e.g. `ls`, `find`, `rg`/`grep`, `git log` / `git blame` / `git show` on existing commits, `file`, `wc`, small read-only pipelines
45
42
  - After `patch` deletes the last file in a `.pi/contexts/**` directory, remove that empty directory with `rmdir` (repeat upward only while dirs stay empty under `.pi/contexts`). Prefer `rmdir` over `rm -r`.
46
43
 
47
44
  Forbidden with bash:
48
45
 
49
- - Anything `ls` / `find` / `grep` / `read` already do cleanly
50
46
  - Creating, editing, moving, or deleting files (catalog files use `patch` only)
51
47
  - Non-empty directory deletes; deletes outside `.pi/contexts`
52
48
  - `git add` / `commit` / `push` / `checkout` / `restore` / `reset` / `stash` / branch changes
@@ -82,7 +78,7 @@ Path stuffing into the nearest feature bucket without climbing the ladder is fai
82
78
 
83
79
  1. `context_sync_evidence` section `overview`.
84
80
  2. `catalog` for the full skeleton. Do not invent domains you never inspected.
85
- 3. Pull `dirty`, `file`, `dependencies`, or `previews` as needed. Use `read` / `ls` / `find` / `grep` for neighbor inspection. Use `bash` only when those cannot cover the question.
81
+ 3. Pull `dirty`, `file`, `dependencies`, or `previews` as needed. Use `read` for known paths. Use `bash` for tree list/search and other inspection evidence cannot cover.
86
82
  4. Edit catalog TOML with `patch`.
87
83
  5. `context_sync_evidence` section `invariants`. If failed, continue until it holds or you can explain a hard blocker.
88
84
  6. Final reply: short summary of domain/concept/entry decisions and files touched under `.pi/contexts`. If no catalog edit was required, say why.
@@ -3,11 +3,19 @@ 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
5
  - read
6
- - grep
7
- - find
8
- - ls
9
6
  - bash
10
- - context_prune
7
+ - outline
8
+ - show
9
+ - discover
10
+ - ast_search
11
+ - deps
12
+ - reverse_deps
13
+ - callers
14
+ - callees
15
+ - references
16
+ - implementations
17
+ - impact
18
+ - context
11
19
  names:
12
20
  - Auditor
13
21
  - Inspector
@@ -15,34 +23,46 @@ names:
15
23
  - Examiner
16
24
  - Sentinel
17
25
  model: openai-codex/gpt-5.6-sol
18
- thinking: xhigh
26
+ thinking: high
19
27
  ---
20
28
 
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.
29
+ Stay inside delegated change. Answer two questions:
30
+
31
+ 1. Is runtime behavior correct?
32
+ 2. Is this the simplest implementation of requested behavior?
33
+
34
+ Find concrete failures or needless complexity. Report. Stop. No mutations, unrelated review, or broad concern inventory.
35
+
36
+ ## Evidence ladder
37
+
38
+ Use cheapest evidence that settles each question. Escalate only when answer could change verdict.
39
+
40
+ 1. **Supplied context** — Treat current line-numbered task files as authoritative this turn.
41
+ 2. **Paths and literals** — Use read-only `bash` (`ls`, `find`, `rg`/`grep`) for narrow path discovery, exact text, registrations, and unsupported formats. Use ranged `read` when formatting or source context matters.
42
+ 3. **Structure and reuse** — Default to `outline`. Use `discover` only when changed code may duplicate an existing repository API but name or path is unknown. Use `ast_search` for a concrete risky or duplicated source shape.
43
+ 4. **Exact declarations** — Use `show` with path + name (+ line when needed). Retrieve only contract, body, imports, or nearby lines needed for verdict.
44
+ 5. **Runtime relationships** — Use `callers`, `callees`, `references`, or `implementations` after selecting a declaration. Use `deps`/`reverse_deps` for file imports. Use `impact` for full blast radius and `context` for one bounded declaration pack.
45
+
46
+ Keep roots and result limits narrow. Structural evidence proves bounded syntax, not dynamic dispatch. Preserve inferred and ambiguous labels.
22
47
 
23
48
  ## Review procedure
24
49
 
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.
50
+ 1. Extract requested behavior, changed scope, and repository constraints from task and supplied files.
51
+ 2. Inspect changed declarations. Form only actionable runtime and simplicity questions.
52
+ 3. Runtime: follow shortest relevant path through callers, state transitions, boundaries, and error handling. Check realistic sequences, not theoretical branch inventory.
53
+ 4. Simplicity: identify wrappers, helpers, option bags, duplicated logic, or staged abstractions that can disappear without changing requested behavior. Report only material reductions in concepts or ownership.
54
+ 5. Inspect surrounding code only to confirm suspected failure, contract mismatch, missed caller, or existing simpler API.
55
+ 6. Stop when both questions have evidence-backed answers.
36
56
 
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.
57
+ Treat implementation as untrusted. Reject speculation, personal style preferences, and complexity complaints without concrete cost. Do not modify files.
38
58
 
39
59
  ## Output
40
60
 
41
- List findings first, ordered by severity. For each finding include:
61
+ List findings first, ordered by severity. Each finding needs:
42
62
 
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.
63
+ - severity and direct title;
64
+ - exact file, line range, and declaration when one exists;
65
+ - runtime failure mechanism or concrete complexity cost;
66
+ - smallest credible fix direction.
47
67
 
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.
68
+ Then list only unresolved questions that materially affect runtime correctness. No findings: say runtime appears correct and implementation is already simplest credible version. Briefly name inspected scope. No preamble, search log, broad summary, or repeated evidence.