little-coder 1.0.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 (76) hide show
  1. package/.pi/extensions/benchmark-profiles/index.ts +159 -0
  2. package/.pi/extensions/benchmark-profiles/profiles.test.ts +78 -0
  3. package/.pi/extensions/browser/index.ts +304 -0
  4. package/.pi/extensions/browser-extract-retention/index.ts +170 -0
  5. package/.pi/extensions/browser-extract-retention/live-integration.test.ts +176 -0
  6. package/.pi/extensions/browser-extract-retention/retention.test.ts +195 -0
  7. package/.pi/extensions/checkpoint/index.ts +66 -0
  8. package/.pi/extensions/evidence/evidence.test.ts +30 -0
  9. package/.pi/extensions/evidence/index.ts +119 -0
  10. package/.pi/extensions/evidence-compact/bridge.test.ts +25 -0
  11. package/.pi/extensions/evidence-compact/index.ts +32 -0
  12. package/.pi/extensions/extra-tools/index.ts +139 -0
  13. package/.pi/extensions/finalize-warn/index.ts +73 -0
  14. package/.pi/extensions/hello/index.ts +7 -0
  15. package/.pi/extensions/knowledge-inject/index.ts +149 -0
  16. package/.pi/extensions/knowledge-inject/scoring.test.ts +81 -0
  17. package/.pi/extensions/llama-cpp-provider/index.ts +58 -0
  18. package/.pi/extensions/output-parser/index.ts +56 -0
  19. package/.pi/extensions/output-parser/parser.test.ts +90 -0
  20. package/.pi/extensions/output-parser/parser.ts +126 -0
  21. package/.pi/extensions/permission-gate/index.ts +53 -0
  22. package/.pi/extensions/permission-gate/permission.test.ts +26 -0
  23. package/.pi/extensions/quality-monitor/index.ts +70 -0
  24. package/.pi/extensions/quality-monitor/quality.test.ts +75 -0
  25. package/.pi/extensions/quality-monitor/quality.ts +84 -0
  26. package/.pi/extensions/shell-session/helpers.test.ts +62 -0
  27. package/.pi/extensions/shell-session/helpers.ts +58 -0
  28. package/.pi/extensions/shell-session/index.ts +139 -0
  29. package/.pi/extensions/skill-inject/frontmatter.test.ts +72 -0
  30. package/.pi/extensions/skill-inject/frontmatter.ts +39 -0
  31. package/.pi/extensions/skill-inject/index.ts +256 -0
  32. package/.pi/extensions/skill-inject/selector.test.ts +91 -0
  33. package/.pi/extensions/thinking-budget/budget.test.ts +182 -0
  34. package/.pi/extensions/thinking-budget/index.ts +105 -0
  35. package/.pi/extensions/tool-gating/index.ts +38 -0
  36. package/.pi/extensions/turn-cap/index.ts +37 -0
  37. package/.pi/extensions/write-guard/index.ts +61 -0
  38. package/.pi/settings.json +76 -0
  39. package/AGENTS.md +61 -0
  40. package/CHANGELOG.md +618 -0
  41. package/LICENSE +201 -0
  42. package/NOTICE +22 -0
  43. package/README.md +245 -0
  44. package/bin/little-coder.mjs +99 -0
  45. package/models.json +45 -0
  46. package/package.json +46 -0
  47. package/skills/knowledge/bfs_state_space.md +9 -0
  48. package/skills/knowledge/binary_search.md +9 -0
  49. package/skills/knowledge/dfs_vs_bfs.md +9 -0
  50. package/skills/knowledge/dynamic_programming.md +9 -0
  51. package/skills/knowledge/hash_vs_tree.md +9 -0
  52. package/skills/knowledge/io_wrapper.md +9 -0
  53. package/skills/knowledge/recursion_backtracking.md +9 -0
  54. package/skills/knowledge/rule_string_transform.md +9 -0
  55. package/skills/knowledge/sorting_choice.md +9 -0
  56. package/skills/knowledge/tree_rerooting.md +9 -0
  57. package/skills/knowledge/tree_zipper.md +9 -0
  58. package/skills/knowledge/two_pointers.md +9 -0
  59. package/skills/knowledge/workspace_docs.md +10 -0
  60. package/skills/protocols/cite_before_answer.md +19 -0
  61. package/skills/protocols/research_protocol.md +20 -0
  62. package/skills/protocols/task_decomposition.md +24 -0
  63. package/skills/tools/agent.md +24 -0
  64. package/skills/tools/bash.md +29 -0
  65. package/skills/tools/browser_click.md +25 -0
  66. package/skills/tools/browser_extract.md +24 -0
  67. package/skills/tools/browser_navigate.md +22 -0
  68. package/skills/tools/browser_type.md +22 -0
  69. package/skills/tools/edit.md +30 -0
  70. package/skills/tools/evidence_add.md +23 -0
  71. package/skills/tools/glob.md +28 -0
  72. package/skills/tools/grep.md +29 -0
  73. package/skills/tools/read.md +28 -0
  74. package/skills/tools/shell_session.md +31 -0
  75. package/skills/tools/webfetch.md +22 -0
  76. package/skills/tools/write.md +29 -0
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: bfs-state-space
3
+ type: domain-knowledge
4
+ topic: State-Space Search
5
+ token_cost: 120
6
+ keywords: [bucket, pouring, state space, minimum moves, shortest sequence, reach goal, transitions, visited states, water, pour, fill, empty]
7
+ user-invocable: false
8
+ ---
9
+ When a problem asks for the MINIMUM number of moves/steps to reach a goal state (bucket pouring, puzzle solving, sliding tiles), model it as BFS over a state space. State = a tuple of all values that fully describe the situation (e.g. (bucket_a, bucket_b)). From each state, enumerate every legal transition (fill A, fill B, empty A, empty B, pour A→B, pour B→A) and produce the next state. Use a visited set keyed on the state tuple to avoid cycles. BFS from the start state; the first time you pop a state matching the goal, its distance is the minimum move count. Track which bucket holds the goal and the other bucket's value at that point. Edge case: if start_bucket is forbidden as an immediate "fill the wrong one first" move, encode that as a filter on the initial transitions.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: binary-search
3
+ type: domain-knowledge
4
+ topic: Binary Search
5
+ token_cost: 90
6
+ keywords: [binary, search, sorted, monotonic, bisect, minimum, maximum, feasible, predicate, lower, upper, bound, log, efficient, mid, pivot, rotated]
7
+ user-invocable: false
8
+ ---
9
+ Binary search works on any monotonic predicate, not just sorted arrays. Pattern: "find minimum X such that condition(X) is true" — binary search on the answer space. Use bisect.bisect_left/bisect_right for sorted-array insertion points. For "minimize the maximum" or "maximize the minimum" problems, binary search on the answer and check feasibility. Always use lo + (hi - lo) // 2 to avoid overflow. When searching rotated arrays, check which half is sorted first. Time: O(log n) — whenever you see "sorted" or "monotonic" in a problem, consider binary search.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: dfs-vs-bfs
3
+ type: domain-knowledge
4
+ topic: Graph Traversal
5
+ token_cost: 100
6
+ keywords: [dfs, bfs, depth, breadth, graph, traverse, path, maze, shortest, connected, reachable, visited, queue, stack, neighbor, walk, flood, fill, island]
7
+ user-invocable: false
8
+ ---
9
+ DFS (stack/recursion) explores one branch fully before backtracking — use for: cycle detection, topological sort, path existence, connected components, backtracking puzzles, flood fill. BFS (queue) explores level-by-level — use for: shortest unweighted path, level-order traversal, nearest neighbor, minimum steps. If the problem asks "shortest" or "minimum steps" on an unweighted graph, always choose BFS. If it asks "all paths," "can we reach," or "count islands," DFS is simpler. Both visit each node once: O(V+E) time.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: dynamic-programming
3
+ type: domain-knowledge
4
+ topic: Dynamic Programming
5
+ token_cost: 110
6
+ keywords: [dynamic programming, dp, memoize, memoization, tabulation, subproblem, overlapping, optimal substructure, fibonacci, knapsack, longest, subsequence, minimum cost, maximum profit, number of ways, climb, stairs, coins, edit distance]
7
+ user-invocable: false
8
+ ---
9
+ Use dynamic programming when a problem has overlapping subproblems (same computation repeated) and optimal substructure (optimal solution built from optimal sub-solutions). Signs: "find minimum cost," "count the number of ways," "longest/shortest subsequence," "can you reach." Define state (what changes between subproblems) and recurrence (how states relate). Top-down with @cache is easiest to write; bottom-up tabulation avoids recursion limits and is often faster. Always check if you can reduce space by keeping only the previous row/state instead of the full table.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: hash-vs-tree
3
+ type: domain-knowledge
4
+ topic: Data Structure Choice
5
+ token_cost: 90
6
+ keywords: [lookup, dictionary, dict, set, hash, hashtable, map, frequency, count, unique, duplicate, ordered, sorted, tree, counter, defaultdict, collections]
7
+ user-invocable: false
8
+ ---
9
+ Use dict/set (hash table, O(1) avg lookup) for: membership testing, frequency counting, deduplication, grouping by key. Use collections.Counter for frequency counts, defaultdict(list) for grouping. When you need ordered keys or range queries, use sorted containers or bisect on a sorted list. For "find if X exists" or "count occurrences," always reach for a set or dict first — never scan a list repeatedly. If the problem involves pairs summing to a target, use a set to check complements in O(n) instead of O(n^2) nested loops.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: io-wrapper
3
+ type: domain-knowledge
4
+ topic: File-Like Wrapper + Counters
5
+ token_cost: 120
6
+ keywords: [io wrapper, wrap file, read counter, write counter, nreads, nwrites, context manager, __enter__, __exit__, passthrough, delegate, paasio, MetaRead, MetaWrite]
7
+ user-invocable: false
8
+ ---
9
+ To wrap a file-like and count reads/writes: store the wrapped object as self._wrapped. Implement read(size=-1) (or readable/readinto as needed) by delegating to self._wrapped.read(size) and incrementing counters by the length of the RETURNED bytes (not the requested size — a short read counts for what it returned). Same for write: call self._wrapped.write(data) and increment nwrites by the RETURN VALUE (number of bytes actually written), or by len(data) if the wrapped write returns None. Expose read_bytes/nreads and write_bytes/nwrites as properties or attributes. Context-manager support: __enter__ returns self; __exit__ calls self._wrapped.__exit__ (or close()) and forwards the exception info. Don't forget close() as a plain method for non-context-manager use. Edge case: thread safety — if the test uses threads, wrap counter updates in a threading.Lock.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: recursion-backtracking
3
+ type: domain-knowledge
4
+ topic: Backtracking
5
+ token_cost: 100
6
+ keywords: [permutation, combination, subset, backtrack, constraint, generate, valid, recursive, pruning, n-queens, sudoku, exhaustive, all, solutions, choose, pick, arrangement, password, sequence]
7
+ user-invocable: false
8
+ ---
9
+ Use backtracking for constraint satisfaction and combinatorial generation: permutations, combinations, subsets, N-queens, sudoku, valid arrangements. Pattern: make a choice, recurse, undo the choice (backtrack). Prune early — skip branches that already violate constraints to avoid exploring dead ends. For subsets: at each element, choose to include or exclude it (2^n total). For permutations: choose each unused element at each position (n! total). Always pass state by reference and undo mutations rather than copying. If the problem says "generate all" or "find all valid," backtracking is usually the right approach.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: rule-string-transform
3
+ type: domain-knowledge
4
+ topic: Ordered-Rule String Transformation
5
+ token_cost: 120
6
+ keywords: [pig latin, string rule, transform word, vowel, consonant, cluster, qu, ordered rules, first match, prefix, suffix, translate word]
7
+ user-invocable: false
8
+ ---
9
+ For rule-based string transforms (pig latin, atbash, rot, etc.): encode the rules as an ordered list of (predicate, transform) pairs. For each word, walk the list; apply the FIRST matching rule and stop. Order matters — specific rules must come before general ones. Pig latin gotchas: (1) a "qu" or consonant-cluster-ending-in-qu counts as a unit — "quick" → "ickquay", "square" → "aresquay"; (2) "y" acts as a consonant at the start but a vowel in the middle — "yellow" → "ellowyay", "rhythm" → "ythmrhay"; (3) the rule order that works is: starts-with-vowel-or-xr-or-yt → append "ay"; starts-with-consonant(s)-then-"qu" → move cluster+qu, append "ay"; starts-with-consonants-up-to-first-"y"-or-vowel → move the consonants, append "ay"; fallback → append "ay". Always test each rule in isolation before combining.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: sorting-choice
3
+ type: domain-knowledge
4
+ topic: Sorting
5
+ token_cost: 90
6
+ keywords: [sort, order, rank, largest, smallest, kth, median, arrange, compare, stable, priority, heap, nlargest, nsmallest, key, reverse, sorted]
7
+ user-invocable: false
8
+ ---
9
+ Python's built-in sorted()/list.sort() is Timsort — O(n log n), stable, and almost always the right choice. Use key= for custom ordering. For top-k elements, use heapq.nlargest/nsmallest (O(n log k)) instead of full sort. For finding just the kth element, consider quickselect or statistics.median. Counting sort / radix sort help only when values are bounded integers. When the problem says "sort by X then by Y," use a tuple key: key=lambda x: (x.a, x.b). For reverse on one field only, negate it or use functools.cmp_to_key.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: tree-rerooting
3
+ type: domain-knowledge
4
+ topic: Tree Re-Rooting (POV)
5
+ token_cost: 120
6
+ keywords: [re-root, reroot, pov, point of view, tree rotation, change root, from_pov, reparent, path between nodes, undirected tree]
7
+ user-invocable: false
8
+ ---
9
+ Re-rooting an undirected tree from a new node: build an undirected adjacency map (parent↔children become symmetric neighbor sets), then do DFS/BFS from the target node. Every node you visit gets its parent set to the node you came from, and its children become all neighbors minus that parent. The result is a new rooted tree with the target as root. Path-between(a, b): re-root at a, then walk from b up parent pointers until you hit a — that gives the reversed path; reverse it for a→b order. If the target node is not in the tree, return None (not an error — many test suites treat "node absent" as None). Cost: O(N) per re-root. Do NOT mutate the original tree when re-rooting — build a fresh node structure, so repeated from_pov calls on the original work correctly.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: tree-zipper
3
+ type: domain-knowledge
4
+ topic: Functional Tree Navigation
5
+ token_cost: 130
6
+ keywords: [zipper, tree navigation, breadcrumb, focus, up, down, left, right, functional tree, immutable tree, cursor]
7
+ user-invocable: false
8
+ ---
9
+ A tree zipper is a cursor for immutable trees. State = (focus, trail). focus is the current subtree. trail is a list of "breadcrumbs" describing the path from root to focus — each crumb remembers the parent's value plus the siblings NOT taken. Operations: down_left/down_right push a crumb (remembering current node + the other child) and make the chosen child the new focus. up pops the top crumb, rebuilds the parent by combining it with the current focus, and makes that parent the new focus. set_value replaces the focused subtree's value. to_tree walks all the way up (repeated up) to rebuild the whole tree. Key invariant: you can always reconstruct the full original tree from (focus, trail) — no information is lost. Equality of two zippers = equality of the fully-reconstructed trees, NOT of the raw (focus, trail) pairs, because different trails can represent the same tree position.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: two-pointers
3
+ type: domain-knowledge
4
+ topic: Two Pointers and Sliding Window
5
+ token_cost: 100
6
+ keywords: [pointer, two, sliding, window, substring, subarray, pair, sum, target, sorted, left, right, fast, slow, cycle, linked, list, contiguous, consecutive, squeeze]
7
+ user-invocable: false
8
+ ---
9
+ Two pointers on a sorted array: start left=0, right=n-1, move inward based on comparison — solves pair-sum, three-sum, container problems in O(n). Sliding window for contiguous subarrays/substrings: expand right boundary, shrink left when constraint violated — solves "longest/shortest substring with property" in O(n). Fast/slow pointers: detect cycles in linked lists (Floyd's), find middle element. Key insight: if brute force is O(n^2) nested loops over a sorted or sequential structure, two pointers likely reduces it to O(n).
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: workspace-docs
3
+ type: domain-knowledge
4
+ topic: Workspace Documentation
5
+ token_cost: 140
6
+ keywords: [implement, build, create, fix, task, exercise, feature, todo, spec, specification, requirements, instructions, bug, test, failing, review, refactor]
7
+ requires_tools: [Read, Glob]
8
+ user-invocable: false
9
+ ---
10
+ Before writing code for a non-trivial task, check if the workspace has a problem specification or convention document. These are cheap to read and often contain the exact format rules, edge cases, or constraints the tests assert — which the model would otherwise have to reverse-engineer from tests alone. Look for (in priority order): `.docs/instructions.md` and `.docs/instructions.append.md` (exercism-style problem specs), `AGENTS.md` / `CLAUDE.md` (agent-specific instructions at repo root), `README.md` in the current directory, `SPEC.md` / `SPECIFICATION.md`, and `docs/*.md`. Use Glob to discover them (`*.md`, `.docs/*.md`, `AGENTS.md`) and Read the relevant one. Do this ONCE at the start of a task, not every turn. If the spec disambiguates a failing test (e.g. "the first and last elements must match" or "spaces and punctuation are excluded"), that single read saves many debug iterations. Skip for pure read-only questions — only invest the Read call when you are about to change code.
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: cite-before-answer
3
+ type: workflow
4
+ triggers: ["/cite"]
5
+ when_to_use: always, before producing a final answer on a research task
6
+ context: inline
7
+ token_cost: 120
8
+ user_invocable: false
9
+ ---
10
+ ## Cite-before-answer checklist
11
+
12
+ Before typing your final answer, run this check internally:
13
+
14
+ 1. Call EvidenceList. Confirm it is non-empty.
15
+ 2. For each claim in your planned answer, identify the evidence id(s) that support it.
16
+ 3. If any claim has no id → either remove the claim, or go gather one more piece of evidence.
17
+ 4. Prefix your final answer with `Citations: e1, e2, …` listing the ids you used.
18
+
19
+ A final answer with zero citations is invalid on research tasks. Do not guess.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: research-protocol
3
+ type: workflow
4
+ triggers: ["/research"]
5
+ when_to_use: when the task requires gathering facts from the web and citing them in a final answer
6
+ context: inline
7
+ token_cost: 180
8
+ user_invocable: false
9
+ ---
10
+ ## Research Protocol (evidence-first)
11
+
12
+ 1. Decompose the question into one or two unknowns. Write them down in your first reply.
13
+ 2. For each unknown, run BrowserNavigate → BrowserExtract → EvidenceAdd (one fact per entry).
14
+ 3. Do NOT state a fact that isn't backed by an EvidenceAdd id.
15
+ 4. Before answering, call EvidenceList. Your answer must reference at least one id.
16
+ 5. If EvidenceList is empty, you are not ready to answer — go back to step 2.
17
+
18
+ Stop conditions:
19
+ - You have an evidence id for every claim in your answer → ANSWER.
20
+ - You have tried 3+ search refinements with no usable evidence → say "insufficient evidence" instead of guessing.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: task-decomposition
3
+ type: workflow
4
+ triggers: ["/decompose"]
5
+ when_to_use: when the task has multiple unknowns or clearly requires multi-step reasoning
6
+ context: inline
7
+ token_cost: 140
8
+ user_invocable: false
9
+ ---
10
+ ## Task Decomposition
11
+
12
+ Before taking ANY tool action, reply with a short decomposition:
13
+
14
+ GIVEN: <one line — what the prompt already states>
15
+ UNKNOWN: <one or two items — what you need to find out>
16
+ PLAN:
17
+ 1. <first tool action, concrete>
18
+ 2. <second tool action>
19
+ 3. <final answer step>
20
+
21
+ Rules:
22
+ - Keep UNKNOWN to 1–2 items. If it grows past 2, split the task further in step 1.
23
+ - Resolve one unknown fully before moving to the next — do NOT interleave.
24
+ - After each tool call, check: did this resolve an UNKNOWN? If yes, strike it. If no, revise the PLAN.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: agent-guidance
3
+ type: tool-guidance
4
+ target_tool: Agent
5
+ priority: 6
6
+ token_cost: 120
7
+ user-invocable: false
8
+ ---
9
+ ## Agent Tool
10
+ Spawn a sub-agent to handle a task autonomously.
11
+
12
+ REQUIRED: prompt (task description for the sub-agent)
13
+ OPTIONAL: subagent_type (coder/reviewer/researcher/tester/general-purpose), name (for messaging), isolation ("worktree" for git isolation)
14
+
15
+ RULES:
16
+ - Use for independent tasks that don't need your direct attention
17
+ - Sub-agents get their own context and can use all tools
18
+ - Use subagent_type to get specialized behavior
19
+ - Use isolation="worktree" when the agent needs to modify files independently
20
+
21
+ EXAMPLE:
22
+ ```tool
23
+ {"name": "Agent", "input": {"prompt": "Find all Python files that import requests and list them", "subagent_type": "researcher"}}
24
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: bash-guidance
3
+ type: tool-guidance
4
+ target_tool: Bash
5
+ priority: 10
6
+ token_cost: 120
7
+ user-invocable: false
8
+ ---
9
+ ## Bash Tool
10
+ Execute a shell command and return stdout+stderr.
11
+
12
+ REQUIRED: command (shell command string)
13
+ OPTIONAL: timeout (seconds, default 30 - use 120-300 for installs/builds)
14
+
15
+ RULES:
16
+ - Stateless: each call starts fresh (cd does not persist)
17
+ - Use absolute paths or chain with && (e.g. "cd /path && make")
18
+ - Use timeout=120 for: pip install, npm install, builds, downloads
19
+ - Returns combined stdout and stderr
20
+
21
+ EXAMPLE:
22
+ ```tool
23
+ {"name": "Bash", "input": {"command": "ls -la /path/to/project/"}}
24
+ ```
25
+
26
+ EXAMPLE with timeout:
27
+ ```tool
28
+ {"name": "Bash", "input": {"command": "pip install requests", "timeout": 120}}
29
+ ```
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: browser-click-guidance
3
+ type: tool-guidance
4
+ target_tool: BrowserClick
5
+ priority: 7
6
+ token_cost: 90
7
+ user-invocable: false
8
+ ---
9
+ ## BrowserClick Tool
10
+ Click an element by CSS selector OR by ARIA role+name.
11
+
12
+ RULES:
13
+ - Prefer role+name over CSS selectors when the element has an accessible name.
14
+ - Never click without first extracting the page — you need to know what links exist.
15
+ - If the click fails with "Error clicking", the selector was probably wrong; extract and choose a different target rather than guessing again.
16
+
17
+ EXAMPLE (role+name):
18
+ ```tool
19
+ {"name": "BrowserClick", "input": {"role": "link", "name": "Edit this page"}}
20
+ ```
21
+
22
+ EXAMPLE (CSS):
23
+ ```tool
24
+ {"name": "BrowserClick", "input": {"selector": "a.external"}}
25
+ ```
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: browser-extract-guidance
3
+ type: tool-guidance
4
+ target_tool: BrowserExtract
5
+ priority: 9
6
+ token_cost: 110
7
+ user-invocable: false
8
+ ---
9
+ ## BrowserExtract Tool
10
+ Return readable markdown of the current page, chunked at ~2KB.
11
+
12
+ OPTIONAL: cursor (char offset, default "0")
13
+
14
+ RULES:
15
+ - First call: use cursor="0" (or omit).
16
+ - The response ends with `[cursor=N next=M total=T has_more=true]`.
17
+ If has_more=true, call again with cursor=M to get the next chunk.
18
+ - When you find the span you want, save it via EvidenceAdd immediately — do not rely on remembering it across turns.
19
+ - If the page is mostly boilerplate (nav/footer), scroll into the article section first (BrowserScroll) before extracting.
20
+
21
+ EXAMPLE:
22
+ ```tool
23
+ {"name": "BrowserExtract", "input": {"cursor": "0"}}
24
+ ```
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: browser-navigate-guidance
3
+ type: tool-guidance
4
+ target_tool: BrowserNavigate
5
+ priority: 8
6
+ token_cost: 80
7
+ user-invocable: false
8
+ ---
9
+ ## BrowserNavigate Tool
10
+ Load a URL in the shared browser page.
11
+
12
+ REQUIRED: url (http:// or https://)
13
+
14
+ RULES:
15
+ - After navigating, ALWAYS call BrowserExtract before BrowserClick. You need the page text to decide what to click.
16
+ - URL must be complete with protocol.
17
+ - Do not navigate the same URL twice in a row; use BrowserBack or scroll instead.
18
+
19
+ EXAMPLE:
20
+ ```tool
21
+ {"name": "BrowserNavigate", "input": {"url": "https://en.wikipedia.org/wiki/Turing_machine"}}
22
+ ```
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: browser-type-guidance
3
+ type: tool-guidance
4
+ target_tool: BrowserType
5
+ priority: 6
6
+ token_cost: 80
7
+ user-invocable: false
8
+ ---
9
+ ## BrowserType Tool
10
+ Fill text into an input element.
11
+
12
+ REQUIRED: selector (CSS), text
13
+ OPTIONAL: submit (bool — press Enter after typing)
14
+
15
+ RULES:
16
+ - For search boxes, use submit=true to execute the search in one call.
17
+ - Selector must uniquely identify the input (e.g. `input[name="q"]`).
18
+
19
+ EXAMPLE:
20
+ ```tool
21
+ {"name": "BrowserType", "input": {"selector": "input[name=\"q\"]", "text": "Alan Turing", "submit": true}}
22
+ ```
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: edit-guidance
3
+ type: tool-guidance
4
+ target_tool: Edit
5
+ priority: 10
6
+ token_cost: 150
7
+ user-invocable: false
8
+ ---
9
+ ## Edit Tool
10
+ Replace exact text in a file. This is the **default tool for changing any existing file** — prefer it over Write for anything except creating a new file from scratch.
11
+
12
+ REQUIRED: file_path (absolute), old_string (exact text to find), new_string (replacement)
13
+ OPTIONAL: replace_all (boolean, replace all occurrences)
14
+
15
+ RULES:
16
+ - old_string must match EXACTLY (whitespace, indentation, line endings all matter)
17
+ - old_string must appear exactly ONCE unless replace_all=true
18
+ - Include enough surrounding context (2-3 lines) to make old_string unique
19
+ - To delete text: set new_string to ""
20
+ - Read the file first if you do not already have its current content
21
+
22
+ EXAMPLE:
23
+ ```tool
24
+ {"name": "Edit", "input": {"file_path": "/absolute/path/file.py", "old_string": "def hello():\n return 1", "new_string": "def hello():\n return 2"}}
25
+ ```
26
+
27
+ RECOVERY WHEN Edit FAILS:
28
+ - "String not found" → Read the file to get the exact current content (whitespace often differs), then retry Edit with the exact string
29
+ - "Found multiple times" → include more surrounding context so old_string is unique, then retry Edit
30
+ - Do NOT fall back to Write just because Edit failed once — re-read, fix old_string, retry. Write is almost always the wrong recovery here for an existing file.
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: evidence-add-guidance
3
+ type: tool-guidance
4
+ target_tool: EvidenceAdd
5
+ priority: 10
6
+ token_cost: 100
7
+ user-invocable: false
8
+ ---
9
+ ## EvidenceAdd Tool
10
+ Save a short citable snippet. Every fact you will put in your final answer must come from an evidence entry.
11
+
12
+ REQUIRED: source (URL or identifier), note (1-line summary), snippet (<=1KB of exact text)
13
+
14
+ RULES:
15
+ - Save the SMALLEST span that supports the claim. Don't dump a paragraph when one sentence is enough.
16
+ - One note = one claim. If a page has three useful facts, store three entries.
17
+ - Snippet must be verbatim from the source, not paraphrased.
18
+ - The returned id is what you cite in your final answer (e.g. `per e3a1f2`).
19
+
20
+ EXAMPLE:
21
+ ```tool
22
+ {"name": "EvidenceAdd", "input": {"source": "https://en.wikipedia.org/wiki/Turing_machine", "note": "Turing machine introduced in 1936", "snippet": "The Turing machine was invented in 1936 by Alan Turing."}}
23
+ ```
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: glob-guidance
3
+ type: tool-guidance
4
+ target_tool: Glob
5
+ priority: 8
6
+ token_cost: 80
7
+ user-invocable: false
8
+ ---
9
+ ## Glob Tool
10
+ Find files matching a glob pattern.
11
+
12
+ REQUIRED: pattern (glob pattern like "**/*.py")
13
+ OPTIONAL: path (directory to search in, defaults to cwd)
14
+
15
+ RULES:
16
+ - Use ** for recursive matching across directories
17
+ - Returns sorted list of matching file paths
18
+ - Good for finding files by extension or name pattern
19
+
20
+ EXAMPLE:
21
+ ```tool
22
+ {"name": "Glob", "input": {"pattern": "**/*.py"}}
23
+ ```
24
+
25
+ EXAMPLE with path:
26
+ ```tool
27
+ {"name": "Glob", "input": {"pattern": "*.md", "path": "/path/to/docs/"}}
28
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: grep-guidance
3
+ type: tool-guidance
4
+ target_tool: Grep
5
+ priority: 8
6
+ token_cost: 100
7
+ user-invocable: false
8
+ ---
9
+ ## Grep Tool
10
+ Search file contents with regex. Uses ripgrep.
11
+
12
+ REQUIRED: pattern (regex pattern)
13
+ OPTIONAL: path (directory/file), include (file glob filter like "*.py"), max_results (limit)
14
+
15
+ RULES:
16
+ - Supports full regex syntax
17
+ - Use include to filter by file type (e.g. "*.py", "*.js")
18
+ - Returns matching lines with file path and line number
19
+ - Good for finding function definitions, imports, references
20
+
21
+ EXAMPLE:
22
+ ```tool
23
+ {"name": "Grep", "input": {"pattern": "def main", "include": "*.py"}}
24
+ ```
25
+
26
+ EXAMPLE with path:
27
+ ```tool
28
+ {"name": "Grep", "input": {"pattern": "TODO|FIXME", "path": "/path/to/project/"}}
29
+ ```
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: read-guidance
3
+ type: tool-guidance
4
+ target_tool: Read
5
+ priority: 10
6
+ token_cost: 100
7
+ user-invocable: false
8
+ ---
9
+ ## Read Tool
10
+ Read a file's contents with line numbers.
11
+
12
+ REQUIRED: file_path (absolute path)
13
+ OPTIONAL: limit (max lines), offset (start line, 0-indexed)
14
+
15
+ RULES:
16
+ - Always use absolute paths, never relative
17
+ - Use limit+offset for large files (read in chunks of 100-200 lines)
18
+ - Returns format: "N\tline_content" (tab-separated line number + content)
19
+
20
+ EXAMPLE:
21
+ ```tool
22
+ {"name": "Read", "input": {"file_path": "/absolute/path/to/file.py"}}
23
+ ```
24
+
25
+ EXAMPLE with range:
26
+ ```tool
27
+ {"name": "Read", "input": {"file_path": "/absolute/path/to/file.py", "limit": 50, "offset": 100}}
28
+ ```
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: shell-session-guidance
3
+ type: tool-guidance
4
+ target_tool: ShellSession
5
+ priority: 10
6
+ token_cost: 140
7
+ user-invocable: false
8
+ ---
9
+ ## ShellSession Tool
10
+ Stateful bash: cd, env vars, and job state persist across calls.
11
+
12
+ REQUIRED: command (one shell command, NOT a script)
13
+ OPTIONAL: timeout (seconds; default 30, use 120–300 for installs/builds)
14
+
15
+ RULES:
16
+ - ONE command per turn. Read the output before proposing the next.
17
+ - State persists: set vars / cd once, reuse later.
18
+ - Never run interactive commands (`vi`, `less`, `top`, `python` bare REPL).
19
+ Use non-interactive equivalents (`cat`, `sed -i`, `python -c '…'`).
20
+ - Output ends with `[exit=N cwd=… timed_out=…]` — check exit=0 before claiming success.
21
+ - If timed_out=true, do NOT just retry; diagnose (longer timeout, narrower command).
22
+
23
+ EXAMPLE:
24
+ ```tool
25
+ {"name": "ShellSession", "input": {"command": "cd /work && ls -la"}}
26
+ ```
27
+
28
+ EXAMPLE with timeout:
29
+ ```tool
30
+ {"name": "ShellSession", "input": {"command": "pip install -q requests", "timeout": 180}}
31
+ ```
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: webfetch-guidance
3
+ type: tool-guidance
4
+ target_tool: WebFetch
5
+ priority: 6
6
+ token_cost: 80
7
+ user-invocable: false
8
+ ---
9
+ ## WebFetch Tool
10
+ Fetch and extract content from a URL.
11
+
12
+ REQUIRED: url (full URL starting with http:// or https://)
13
+
14
+ RULES:
15
+ - Always use complete URLs with protocol
16
+ - Returns extracted text content (HTML stripped)
17
+ - Good for reading documentation, API references, web pages
18
+
19
+ EXAMPLE:
20
+ ```tool
21
+ {"name": "WebFetch", "input": {"url": "https://docs.python.org/3/library/json.html"}}
22
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: write-guidance
3
+ type: tool-guidance
4
+ target_tool: Write
5
+ priority: 10
6
+ token_cost: 110
7
+ user-invocable: false
8
+ ---
9
+ ## Write Tool
10
+ Create a **new** file with the given content. Creates parent directories automatically.
11
+
12
+ REQUIRED: file_path (absolute), content (full file content)
13
+
14
+ **Write is for creating new files only.** If the file already exists, Write will be **refused** by the tool and return an error telling you to use Edit instead. Do not retry Write on the same path — it will be refused again.
15
+
16
+ WHEN TO USE Write:
17
+ - The file does not exist yet and you are creating it from scratch
18
+
19
+ WHEN TO USE Edit INSTEAD:
20
+ - ANY change to an existing file — bug fixes, refactors, format tweaks, adding a function, renaming a variable, everything. Edit takes old_string + new_string and patches in place.
21
+ - Iterating after a failed test — never retype the whole file
22
+
23
+ If you need to completely replace an existing file's content, Edit can still do that: pass the entire current content as old_string and the full new content as new_string. Read the file first if you don't already have its current content.
24
+
25
+ EXAMPLE:
26
+ ```tool
27
+ {"name": "Write", "input": {"file_path": "/tmp/example/new_module.py", "content": "def hello():\n return 'hi'\n"}}
28
+ ```
29
+ NOTE: Always use the EXACT file path given in the task, never a placeholder.