Add common baseline agentic tools #155

Closed
opened 2026-08-12 17:41:28 +00:00 by coilysiren · 6 comments
Owner

web search, list local files, search local files, create file, etc...

web search, list local files, search local files, create file, etc...
Member

Scope decision: the full set, against a real workspace

Direction from Kai, 2026-08-12 session. This issue was one line, and each verb in it is a different question, so recording what was chosen and what it commits us to.

web search, list local files, search local files, create file, etc...

All of it, backed by a persistent workspace, rather than web search alone or folding the file verbs into #156's per-turn virtual file.

The thing this issue does not say, which decides its shape

Deep runs in a k3s pod with no repository checkout. There is no "local" filesystem today. So "list local files" is not a tool that reads something already present, it is a request to create a filesystem and then expose it. That is the actual work, and it is why this is not the small ticket its body suggests.

The workspace has to be declared before any verb is written: where it is mounted, whether it persists across pod restarts, and whether it is shared across requesters or partitioned per requester. The last one matters most. A shared workspace means anything one requester writes, another can read, which is a data path between accounts that the access policy does not currently model.

Two constraints, named rather than treated as blockers

1. This is an authority widening, and ward / cli-guard govern that class. Deep is Discord-facing. Giving it a persistent write surface is a different posture from read-and-reply plus bounded Forgejo writes, and it is the kind of grant #150's per-requester authority work exists to express. It should not arrive as an implicit consequence of adding tools. Same reasoning #127 landed on: a bound supplied by the thing being bounded is not a bound.

2. It compounds #162 directly. Deep already ships a 53 KB system prompt on every turn, of which 17 tool schemas are a large share, and a tool was used in only 8 of 46 turns. Every verb added here is paid on every turn including a four-byte ping. #162's own recommendation is a narrower default roster. These two issues pull in opposite directions and the tension should be resolved deliberately rather than by whichever lands last.

The resolution I would take: make the roster selectable per turn rather than growing the default set, so the file verbs are present when a turn needs them and absent from the prefix when it does not. That serves both issues instead of trading one off.

Still undefined, and needed before code

  • Workspace lifetime and partitioning - persistent or ephemeral, shared or per-requester.
  • Size ceiling and eviction. Unbounded write from a Discord message is a disk-exhaustion path on a shared node.
  • Web search provider and egress. Which provider, whether the cluster has egress for it, and what it costs per turn. This is the one verb with no filesystem question attached and could land first on its own.
  • Relationship to #156. That issue creates a per-turn virtual file for large prompt bodies. If this workspace exists, #156's file should live inside it rather than being a second, separate file concept with its own lifetime rules.
  • Whether create file implies delete file and edit file. The "etc" is doing real work in the issue body and each verb is its own authority question.

Suggested sequencing

Web search first, since it is independently useful and carries none of the filesystem questions. Then the workspace declaration with its ward grant. Then the file verbs against it, with #156 folded in as the ingress path rather than built separately.

## Scope decision: the full set, against a real workspace Direction from Kai, 2026-08-12 session. This issue was one line, and each verb in it is a different question, so recording what was chosen and what it commits us to. > web search, list local files, search local files, create file, etc... **All of it, backed by a persistent workspace**, rather than web search alone or folding the file verbs into #156's per-turn virtual file. ## The thing this issue does not say, which decides its shape Deep runs in a k3s pod with no repository checkout. **There is no "local" filesystem today.** So "list local files" is not a tool that reads something already present, it is a request to create a filesystem and then expose it. That is the actual work, and it is why this is not the small ticket its body suggests. The workspace has to be declared before any verb is written: where it is mounted, whether it persists across pod restarts, and whether it is shared across requesters or partitioned per requester. The last one matters most. A shared workspace means anything one requester writes, another can read, which is a data path between accounts that the access policy does not currently model. ## Two constraints, named rather than treated as blockers **1. This is an authority widening, and `ward` / `cli-guard` govern that class.** Deep is Discord-facing. Giving it a persistent write surface is a different posture from read-and-reply plus bounded Forgejo writes, and it is the kind of grant #150's per-requester authority work exists to express. It should not arrive as an implicit consequence of adding tools. Same reasoning #127 landed on: a bound supplied by the thing being bounded is not a bound. **2. It compounds #162 directly.** Deep already ships a 53 KB system prompt on every turn, of which 17 tool schemas are a large share, and a tool was used in only 8 of 46 turns. Every verb added here is paid on every turn including a four-byte `ping`. #162's own recommendation is a *narrower* default roster. These two issues pull in opposite directions and the tension should be resolved deliberately rather than by whichever lands last. The resolution I would take: make the roster selectable per turn rather than growing the default set, so the file verbs are present when a turn needs them and absent from the prefix when it does not. That serves both issues instead of trading one off. ## Still undefined, and needed before code * **Workspace lifetime and partitioning** - persistent or ephemeral, shared or per-requester. * **Size ceiling and eviction.** Unbounded write from a Discord message is a disk-exhaustion path on a shared node. * **Web search provider and egress.** Which provider, whether the cluster has egress for it, and what it costs per turn. This is the one verb with no filesystem question attached and could land first on its own. * **Relationship to #156.** That issue creates a per-turn virtual file for large prompt bodies. If this workspace exists, #156's file should live inside it rather than being a second, separate file concept with its own lifetime rules. * **Whether `create file` implies `delete file` and `edit file`.** The "etc" is doing real work in the issue body and each verb is its own authority question. ## Suggested sequencing Web search first, since it is independently useful and carries none of the filesystem questions. Then the workspace declaration with its ward grant. Then the file verbs against it, with #156 folded in as the ingress path rather than built separately.
Member

Correction to constraint 2 above, now that the prefix has been measured rather than estimated.

The scope comment argues these tools compound #162, on the grounds that "17 tool schemas are a large share" of the 53 KB prefix. That was the best available reading at the time. It does not survive measurement.

Agent Proxy now records request shape and provider cache accounting on every request.chat span. Across ~17 organic Deep turns:

measured
system prompt bytes 54,304 avg
tool schema bytes 7,029 avg
tool count 17
prompt cache hit rate 99.17%

Tool schemas are about 11% of the request. The system prompt is about 89%. And the route was already cached, at roughly 112 uncached tokens per turn, so the marginal cost of a handful of new verbs is 11% of a prefix that is close to free.

What this changes. The proposed resolution was to make the roster selectable per turn rather than growing the default set. That is real engineering, and it exists to dodge a cost that turns out to be small. Worth reconsidering on the numbers before anyone builds per-turn roster selection, because #162's own framing was corrected in the same measurement pass and no longer asks for a narrower default on cost grounds.

What survives. Two arguments against a wide default roster remain, and neither is about bytes:

  1. Authority. Constraint 1 in the scope comment is untouched. A persistent write surface on a Discord-facing agent is a posture change regardless of what it costs to ship, and #179 now draws that line explicitly.
  2. Attention. 17 schemas resident while a tool fires on 8 of 46 turns is a selection-accuracy question. More resident tools is not free accuracy, and caching does nothing for it.

If the roster gets narrowed, the case should be made and measured on tool-selection accuracy rather than prompt size. gen_ai.request.tool_count and gen_ai.request.tool_bytes are on every span, so a before and after is easy, but the byte delta will be small and is not the point.

Full numbers and method on #162. Origin measurement corrected on agent-proxy#101.

**Correction to constraint 2 above, now that the prefix has been measured rather than estimated.** The scope comment argues these tools compound #162, on the grounds that "17 tool schemas are a large share" of the 53 KB prefix. That was the best available reading at the time. It does not survive measurement. Agent Proxy now records request shape and provider cache accounting on every `request.chat` span. Across ~17 organic Deep turns: | | measured | |---|---| | system prompt bytes | 54,304 avg | | tool schema bytes | **7,029 avg** | | tool count | 17 | | prompt cache hit rate | **99.17%** | Tool schemas are about **11%** of the request. The system prompt is about **89%**. And the route was already cached, at roughly 112 uncached tokens per turn, so the marginal cost of a handful of new verbs is 11% of a prefix that is close to free. **What this changes.** The proposed resolution was to make the roster selectable per turn rather than growing the default set. That is real engineering, and it exists to dodge a cost that turns out to be small. Worth reconsidering on the numbers before anyone builds per-turn roster selection, because #162's own framing was corrected in the same measurement pass and no longer asks for a narrower default on cost grounds. **What survives.** Two arguments against a wide default roster remain, and neither is about bytes: 1. **Authority.** Constraint 1 in the scope comment is untouched. A persistent write surface on a Discord-facing agent is a posture change regardless of what it costs to ship, and #179 now draws that line explicitly. 2. **Attention.** 17 schemas resident while a tool fires on 8 of 46 turns is a selection-accuracy question. More resident tools is not free accuracy, and caching does nothing for it. If the roster gets narrowed, the case should be made and measured on tool-selection accuracy rather than prompt size. `gen_ai.request.tool_count` and `gen_ai.request.tool_bytes` are on every span, so a before and after is easy, but the byte delta will be small and is not the point. Full numbers and method on #162. Origin measurement corrected on [agent-proxy#101](https://forgejo.coilysiren.me/coilyco-flight-deck/agent-proxy/issues/101).
Member

Design decision — all three tool groups approved

Recorded by Delphi (design seat, standing in for exec). Kai's decision, 2026-08-12.

The body says "web search, list local files, search local files, create file, etc..."all of it lands. Kai took every group offered and declined to defer the set past August 19.

Group Scope
Web search Search the web
Local file read + search List files, search file contents
File create / write Produce files

Web search — two things it changes

It makes the link-out regime honest. Kai decided Echo should answer encyclopedia-shaped questions briefly and link an authoritative source (#213, #222). Without search, that link comes from model memory — a remembered URL, which is a citation with the same reliability as the llama plot (#233). With search, the link is retrieved and real. Search is what turns the link-out decision from a hope into a mechanism.

It is the prime data-borne injection vector. #177 makes the point that the vector that matters is not the chat box but instructions smuggled inside data. Search results are attacker-influenceable data entering the context. That issue's case class should cover this tool specifically, and Quail should treat it as a gating-eval concern per #191.

File tools — bound the write, and build the substrate once

Read and search sit comfortably inside the blast-radius line (#179) — read-only and reversible.

File create/write is a write capability and needs a boundary. Bounded to a scratch workspace it is reversible and inside the line; unbounded it is not. That boundary is the implementer's responsibility, not a detail — per 179, irreversible action is tier 2.

Critically: this is the fourth approved capability wanting the same turn-scoped file substrate. The others are image reading (#168), large prompt bodies (#156), and automatic MCP output spooling (#217). Build it once. Four independent implementations of "a file the agent can touch" is how four incompatible notions of lifetime and scope get shipped.

Deployment dependency: coilyco-bridge/deploy#392, approved to land before August 19 — though scoped to Deep, and Echo's equivalent is unconfirmed.

Capability accounting

Every tool here widens what Echo can truthfully claim about itself. The ceiling work in #200 should be regenerable rather than hand-written, because the roster is now moving fast — Steam and the broader gaming MCPs (#229) plus these four.

## Design decision — all three tool groups approved Recorded by Delphi (design seat, standing in for exec). Kai's decision, 2026-08-12. The body says *"web search, list local files, search local files, create file, etc..."* — **all of it lands.** Kai took every group offered and declined to defer the set past August 19. | Group | Scope | | --- | --- | | **Web search** | Search the web | | **Local file read + search** | List files, search file contents | | **File create / write** | Produce files | ### Web search — two things it changes **It makes the link-out regime honest.** Kai decided Echo should answer encyclopedia-shaped questions briefly and **link an authoritative source** (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/213, https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/222). Without search, that link comes from model memory — a remembered URL, which is a citation with the same reliability as the llama plot (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/233). With search, the link is retrieved and real. **Search is what turns the link-out decision from a hope into a mechanism.** **It is the prime data-borne injection vector.** https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/177 makes the point that the vector that matters is not the chat box but instructions smuggled inside data. Search results are attacker-influenceable data entering the context. That issue's case class should cover this tool specifically, and Quail should treat it as a gating-eval concern per https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/191. ### File tools — bound the write, and build the substrate once Read and search sit comfortably inside the blast-radius line (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/179) — read-only and reversible. **File create/write is a write capability and needs a boundary.** Bounded to a scratch workspace it is reversible and inside the line; unbounded it is not. That boundary is the implementer's responsibility, not a detail — per 179, irreversible action is tier 2. Critically: **this is the fourth approved capability wanting the same turn-scoped file substrate.** The others are image reading (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/168), large prompt bodies (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/156), and automatic MCP output spooling (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/217). **Build it once.** Four independent implementations of "a file the agent can touch" is how four incompatible notions of lifetime and scope get shipped. Deployment dependency: https://forgejo.coilysiren.me/coilyco-bridge/deploy/issues/392, approved to land before August 19 — though scoped to Deep, and Echo's equivalent is unconfirmed. ### Capability accounting Every tool here widens what Echo can truthfully claim about itself. The ceiling work in https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/200 should be **regenerable** rather than hand-written, because the roster is now moving fast — Steam and the broader gaming MCPs (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/229) plus these four.
Member

CLAIM — Angie (ENG, claude seat) · 2026-08-13T15:12Z · 20 min. Approved at 07:44Z with the approval as the last comment, which is the decided-and-forgotten shape I wrote up on #315.

Waiting the buffer. Checking what of the three groups already exists before building anything, because I suspect most of this is closer than it reads.

**CLAIM — Angie (ENG, claude seat)** · 2026-08-13T15:12Z · 20 min. Approved at 07:44Z with the approval as the last comment, which is the decided-and-forgotten shape I wrote up on https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/315. Waiting the buffer. Checking what of the three groups already exists before building anything, because I suspect most of this is closer than it reads.
Member

Two of your three groups are already built, and the third is not harness work — Angie (ENG, claude seat). Checked rather than assumed, because this read like three features and is closer to one. Releasing the claim.

Groups 2 and 3 exist today

internal/community/scratch.go already serves exactly what the body asked for:

you asked for tool
list local files scratch_list
search local files scratch_search
create file scratch_write
(also) scratch_read

Bounded: 256 KB per file, 200 entries, 100 matches, 8 directories deep, partitioned per requester.

They were inert on Echo because the deployment never set SIRENS_ECHO_SCRATCH. That is the switch you approved on #287 at 07:57Z, and it is now built and mergeable at coilyco-bridge/deploy#445, held only on the capability-doc fix #389 which is also built.

So two thirds of this issue ships the moment that rollout happens. No code was needed and none was written.

Group 1 is a roster grant, not a harness change

Echo's roster has three servers: eco, forgejo, steam. There is no search server anywhere to add. Web search needs one deployed first, which is deploy-side work rather than anything I can build here.

Filed separately so it is actionable rather than buried in a three-group issue that is otherwise done.

The part of Delphi's note that should survive into that work

It is the prime data-borne injection vector.

That is right and it is now cheaper to handle than it was this morning. The content gate landed today (#388), so a classifier seam exists — but it classifies the member's request, not tool output. Search results arriving as trusted context is a different boundary and #177 is where it belongs.

Recommendation: do not enable web search before that is answered. The link-out honesty win is real, and so is handing an untrusted document straight into the prompt.

**Two of your three groups are already built, and the third is not harness work — Angie (ENG, claude seat).** Checked rather than assumed, because this read like three features and is closer to one. Releasing the claim. ## Groups 2 and 3 exist today `internal/community/scratch.go` already serves exactly what the body asked for: | you asked for | tool | | --- | --- | | list local files | `scratch_list` | | search local files | `scratch_search` | | create file | `scratch_write` | | (also) | `scratch_read` | Bounded: 256 KB per file, 200 entries, 100 matches, 8 directories deep, partitioned per requester. **They were inert on Echo because the deployment never set `SIRENS_ECHO_SCRATCH`.** That is the switch you approved on https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/287 at 07:57Z, and it is now built and mergeable at https://forgejo.coilysiren.me/coilyco-bridge/deploy/pulls/445, held only on the capability-doc fix https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/389 which is also built. **So two thirds of this issue ships the moment that rollout happens.** No code was needed and none was written. ## Group 1 is a roster grant, not a harness change Echo's roster has three servers: eco, forgejo, steam. **There is no search server anywhere to add.** Web search needs one deployed first, which is deploy-side work rather than anything I can build here. Filed separately so it is actionable rather than buried in a three-group issue that is otherwise done. ## The part of Delphi's note that should survive into that work > It is the prime data-borne injection vector. That is right and it is now cheaper to handle than it was this morning. The content gate landed today (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/388), so a classifier seam exists — but it classifies the **member's request**, not tool output. Search results arriving as trusted context is a different boundary and https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/177 is where it belongs. **Recommendation: do not enable web search before that is answered.** The link-out honesty win is real, and so is handing an untrusted document straight into the prompt.
Member

Closing: two of your three groups were already built and the third is tracked where it belongs — Angie (ENG, claude seat).

You asked for "web search, list local files, search local files, create file, etc..." and Kai approved all three groups.

Groups two and three exist and ship with the scratchpad rollout. scratch_list, scratch_search, scratch_write, scratch_read, bounded and partitioned per requester. They were inert on Echo only because the deployment never set the switch — which Kai approved on #287 and which is built at coilyco-bridge/deploy#445. No code was needed for that half and none was written.

Group one has no server to grant. Echo's roster is eco, forgejo, steam. Web search needs one deployed first, which is coilyco-bridge/deploy#448.

So everything this issue asks for is either delivered or has its own home. Keeping it open makes it a second place to watch the same deploy, which is the readability failure #437 measured the cost of.

One thing worth carrying to 448 rather than losing here: Delphi's note that search results are the prime data-borne injection vector. The content gate landed today but classifies the member's request, not tool output, so an approved host serving hostile instructions is still open on #177. Worth answering before search is enabled in a member-facing channel, not after.

**Closing: two of your three groups were already built and the third is tracked where it belongs — Angie (ENG, claude seat).** You asked for *"web search, list local files, search local files, create file, etc..."* and Kai approved all three groups. **Groups two and three exist and ship with the scratchpad rollout.** `scratch_list`, `scratch_search`, `scratch_write`, `scratch_read`, bounded and partitioned per requester. They were inert on Echo only because the deployment never set the switch — which Kai approved on https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/287 and which is built at https://forgejo.coilysiren.me/coilyco-bridge/deploy/pulls/445. No code was needed for that half and none was written. **Group one has no server to grant.** Echo's roster is eco, forgejo, steam. Web search needs one deployed first, which is https://forgejo.coilysiren.me/coilyco-bridge/deploy/issues/448. So everything this issue asks for is either delivered or has its own home. **Keeping it open makes it a second place to watch the same deploy**, which is the readability failure https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/437 measured the cost of. One thing worth carrying to 448 rather than losing here: Delphi's note that search results are the prime data-borne injection vector. The content gate landed today but classifies the **member's request**, not tool output, so an approved host serving hostile instructions is still open on https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/177. Worth answering before search is enabled in a member-facing channel, not after.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo#155
No description provided.