Skip to content

agent: true read-only mode that does not register mutable tools #2271

Description

@defangdevs

Describe the issue

Follow-up from #2269 / #2270, requested by @lionello: "we need a read-only mode, agent without mutable tools."

#2270 makes each write-capable agent tool handler (deploy, destroy, set_config, remove_config) refuse up front when elicitations.Controller.IsSupported() is false — i.e. when there's no user to confirm with. The tools are still registered and offered to the model; they just no-op-and-report an error at call time. That fixes the specific incident (unattended CI debugger silently mutating production) but isn't the same thing as a read-only mode.

This issue is about the broader ask: a mode where mutable tools are never registered/offered to the model at all, so the model can't even attempt a write — closer to the "gate registration in agent.go" variant that was considered and set aside for #2270 in favor of the narrower per-handler-refusal fix (see #2269's plan comment).

Where this would live

src/pkg/agent/agent.go's New() builds the tool list unconditionally:

defangTools := tools.CollectDefangTools(ec, tools.StackConfig{...})
toolManager.RegisterTools(defangTools...)

tools.CollectDefangTools (src/pkg/agent/tools/tools.go) returns one flat []ai.Tool including deploy, destroy, set_config, remove_config alongside read-only tools (services, logs, estimate, list_configs, current_stack, ...).

Proposed shape

  • Add a ReadOnly bool (or similar) to StackConfig, or a new agent.Option (e.g. WithReadOnly()), that CollectDefangTools uses to skip the four write-capable tool constructors entirely.
  • Decide how it's exposed: a CLI flag on the debugger invocation, an MCP integration setting, or both — the sibling hook session that flagged this noted it could be reusable beyond the CI-debugger path (e.g. for MCP).
  • WithNonInteractive() (used only by the CI debugger) and a future WithReadOnly() are orthogonal: the CI debugger today wants non-interactive and now has per-handler refusal (agent: refuse debugger writes when there is no one to confirm them #2270); a read-only mode might be requested independently by an interactive session too (e.g. someone deliberately wants read-only chat access).
  • agent: refuse debugger writes when there is no one to confirm them #2270's per-handler refusal stays as defense in depth regardless — this issue doesn't replace it, it adds a second layer that also stops the model from seeing the tools in the first place.

Not decided yet

Referenced from #2269.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions