Skip to content

Agent Behaviour: get_behaviour / set_behaviour, with guardrails excluded from self-writes #224

Description

@serge-ivo

Depends on #223.

Why

The user's requirement is that this works conversationally: "I want it to read it back to me, and if
I ask to add or amend it, it should be able to do it."
Today the agent fakes this — it wrote its
character preference into Memory and then read that back, which looks right and is stored in the
wrong place.

Scope

Two FIRST_PARTY_TOOLS entries deriving their argument schema from BEHAVIOUR_FIELDS, so adding a
field never means editing the tools:

  • get_behaviour — returns the resolved values with their band prose, so the agent can explain
    itself in the same words the prompt uses rather than reciting numbers.
  • set_behaviour — partial patch through sanitizeBehaviour; returns the full post-patch object
    (same convention as the memory tools, so the model sees what it actually changed).

Security boundary — non-negotiable

set_behaviour must NOT be able to write the guardrail fields (topicRestrictions,
blockedTerms, requireCitations). Those stay UI-only.

The reason is concrete: a Repo Coder reads untrusted repo files and GitHub issue bodies. If injected
text can widen the agent's own guardrails, the guardrails are decorative. Presentation preferences
are low-stakes and self-correcting — a user who gets an unwanted tone says so. A silently removed
topic restriction is not observable.

Enforced by a SELF_WRITABLE allowlist in lib/agent-behaviour.ts, with a test that fails if any
guardrail field ever becomes self-writable.

Note these are ungated like start_work and run_pipeline — the consent gate keys on a connector,
so a scope-write tool without one is unreachable rather than gated. The allowlist above is the real
boundary here, not the scope field.

Verification

  • A patch naming a guardrail field is rejected, and the surrounding legitimate fields still apply
    (partial rejection, not silent whole-patch failure).
  • Round-trip: set_behaviour → prompt rebuild → the new band prose is present.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions