PKU harness
Concepts

Permissions and consent

For each effect of each plugin, you decide whether the agent may act directly, must ask first, or may not act at all. Scheduled runs only read.

Once you accept the terms during first-run setup, the agent may use your enabled plugins on your behalf.

You can still control in detail what the agent may do. Each plugin has a separate setting, called a mode, for each effect. For example, you can let the agent check your campus-card balance directly but ask you before it recharges the card. You change modes in Settings → Plugins → plugin → AI permissions.

The three modes

The mode decides what happens when the agent calls a tool with that effect.

ModeResult
autoThe tool runs directly
askAn approval prompt appears first
offThe call is refused

The approval prompt shows the plugin, the tool, the effect and the inputs. It offers three choices: Allow, Deny and Always allow.

When the mode is off, the call is refused and the agent is told that the tool is blocked.

Default modes

Each kind of plugin has its own defaults.

Plugin kindreadwritemoneypublic
Bundled pluginautoautoautoauto
Official plugin documentautoautoautoauto
Community plugin documentautoaskaskask
Remote pluginautoaskaskask

A plugin can change its own defaults with defaultModes.

  • For bundled plugins and official plugin documents, defaultModes applies as declared, for example { money: 'ask' }. Effects that it doesn't mention stay auto.
  • Community plugin documents can also set defaultModes, but only settings stricter than the table above take effect.

If users would want to confirm an action first, declare a stricter default for it:

definePlugin({
  // …
  defaultModes: { money: 'ask', public: 'ask' },
});

Who is asked, and when

Whether a call runs is decided in one place only, the host's invoke path. The host checks in this order.

  1. The tool must exist, and its plugin must be available (its capabilities are met) and enabled.
  2. A userOnly tool is refused unless actor === 'user'.
  3. The input is validated against the tool's zod schema.
  4. If the mode is off, the call is refused.
  5. If actor === 'scheduler' and the effect is not read, the call is refused. Unattended runs can only read.
  6. If the mode is ask and actor === 'scheduler', the call is declined, because there is nobody to ask.
  7. If the mode is ask and actor === 'agent', an approval prompt appears. If you deny it, the agent receives a "declined" error.
  8. If actor === 'user', there is never a prompt, because tapping a button already shows what you want.

Tools that always ask

Two kinds of tool ask on every agent call, whatever the mode says. auto never skips the prompt, off still blocks the call, and scheduled calls are refused.

  • A grant tool gives the agent access it doesn't have yet, for example copilot.requestApp, which adds an app to Copilot's scope. Its prompt offers Allow once, Always allow and Don't allow. The answer reaches the tool as ctx.grant ('once' or 'always') and never changes the plugin's modes.
  • An alwaysAsk tool is for actions the host can't judge from an observed target. Its prompt has no "always allow" option.

When a tool's resolveEffect names a target (for example the button Copilot is about to tap), the prompt shows it as the headline and doesn't offer "always allow" either.

Besides tool calls, a few other things need your consent separately.

Campus services. When you sign in to your campus account, you allow the app to reach campus services. A plugin declares the sites and services it uses (scopes) and requires: ['campus-session']. These are shown on the plugin's page.

PKU harness Cloud. Each plugin has its own Allow cloud switch. Next to the switch, the app lists the plugin's disclosure lines, which say in plain words what the plugin stores online. A cloud call made without consent throws CloudError('consent_required'). See Cloud.

Files. Only you can choose files. A plugin may call services.files.pick from a screen, and never from a tool that the agent calls. Documents you attach in chat are read into text on the phone, and the agent pages through and searches them with the core files plugin's tools. Those tools return third-party content, so calling one marks the agent's turn as tainted.

Notifications and exact alarms. These are granted through the system's permission prompts. A plugin shows the prompt by calling services.notify.fix(kind) when you tap.

Memory. If the agent writes a memory after it has read untrusted content, the memory is saved as pending. It takes effect only after you approve it on the memory screen.

Settings, including the modes themselves. The agent can change settings through the core settings plugin: the app's appearance, language and time zone, the model, each plugin's switch, each plugin's modes and each plugin's preferences. The change tool has the write effect, so it follows the settings plugin's own mode, which is auto by default like any bundled plugin. A user who wants to confirm every settings change sets that mode to ask. Secrets and steps that need the user's hands (API keys, the campus account, system permissions) are uiOnly: the agent can only open their screen. See Architecture → The agent operates everything.

Rules for plugin authors

  • You must declare each tool's effect honestly. The money and public effects exist so that users can keep those actions behind a confirmation.
  • You must not hide a write inside a read tool, for example "read and mark as seen".
  • You should set defaultModes to ask for money and public, unless the action is easy to undo.
  • You should split a tool that both reads and writes into two tools.
  • You must use userOnly for actions that the agent must not start itself, for example approving a memory the agent wrote.

On this page