The GitHub add-on refused classic tokens in the page only, and its
repository list took exact owner/name entries.
A classic token (ghp_) is now an explicit choice of the connection. The
kind declares a token guard: the host refuses a token with that prefix
unless the connection sets the option classicToken to allow, and the
request that turns it on must carry confirm_wider_token. It is checked
when the token is saved and again each time it is used, so switching
the option off stops a stored token. The list and the write mode still
apply. The page shows a warning and two ticks.
The list takes owner/* and *. The host matches them before the add-on
runs, without regard to case and on whole names, so other-owner/x and
owner-evil/x are not covered by acme/*, and a key that holds a star is
never a name. A kind opts in with wildcardResources; only GitHub does,
so the other add-ons keep exact matching. Saving * needs
confirm_any_resource, and the write mode stays separate. A read tool
that declares enumerates (the new list-repos) runs only for a list of *
and asks GitHub which repositories the token reaches.
Assisted-by: Claude:claude-sonnet-5-5
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
The manifest said its text in English only. An add-on can now translate
what the host shows to people, and the library list shows it before the
add-on is installed.
The title and the description use the language maps of ui.title and
ui.description, which every host already reads. A new optional field,
i18n, translates the connector kinds by language tag. It stays under api
2 and its set of fields is closed: the title and the description of a
declared kind, and only where the English kind has them. Tool
descriptions, schemas and skills are for the model and stay English.
Tags follow the language map rule (at most 16, no English), each string
has the limit of its English field, all translated text has at most
12 000 characters, and markup, control characters and direction
overrides are refused. A host that does not know the field refuses the
manifest, as it refuses any unknown field. The field is part of the
manifest, so the package digest and the signature cover it.
The catalog generator copies the translated title and description of
the manifest into each library entry (ui.titles, ui.descriptions), the
host validates them like the manifest values, and a library search
matches the English and the translated text. The apps list and the
connector kinds return the text of every language and, when the request
names a language (lang, else Accept-Language), the resolved text beside
the English fields: language, localizedTitle and localizedDescription.
No existing field changes.
Every add-on on master now has its title and description in Italian,
German, Spanish, French, Brazilian Portuguese, Simplified Chinese,
Korean and Indonesian, and the chat connectors carry their kind text in
the same languages. The packaging tests require that, and that a
translation has the fields of the English text it translates. The names
of the add-ons that provide a role are matched in their English title
only: a translation is often an ordinary word of its language.
Assisted-by: Claude:claude-sonnet-5-5 go
A chat never uses a connection that the host picked for it. For an add-on
whose tools run with the token of a connection (such as GitHub):
- With one connection, it is selected. With several, the Tools menu row
of the add-on has a Connection selector, and until the person picks one
the tools are not offered and the row says so. With none, the row says
so and links to the Connectors page. The choice is stored with the chat
and its draft, like the other switches, and follows a fork, a
sub-agent and the runs of a trigger the chat proposed.
- A saved agent can name its connection per add-on (agent form field, API
field connections). Its chats use it, show it read only and cannot
change it. An agent with no choice follows the same rule as a chat. A
chat that a connector binding started keeps using that binding.
- CredentialFor takes the selected binding and uses only it, so the
resource list of that binding is the only one that applies. A call with
no selected binding is refused with the code select_connection and a
note the model can relay. The first-match code (connectors.Pick) is
removed.
- Tool results and proposal cards say which connection acted, for example
"as Work, repository acme/widgets". A proposal is applied with the
connection it was previewed with. The credential use is logged with the
binding ID.
Contract: the credential slot takes an optional resourceLabel (the word
for the resource in that line). The agent export file does not carry the
connections, since a binding ID belongs to one server.
Assisted-by: Claude:claude-sonnet-5-5 go gofmt ginkgo node playwright protoc swag
A GitHub write that waits for the person used to show the raw preview
JSON in the host's approval frame. The add-on now declares an
approval-card component for each of its six write tools. It shows what
will be done, where (with a link to the issue or pull request), as which
connection, and the exact stored text that will be posted, plus a note
that the text is public.
The proposal does not name the connection, so the card reads the saved
connections and names the one that lists the repository.
Assisted-by: Claude:claude-sonnet-5-5 node playwright eslint
A connector kind can declare agentOptional. A binding of such a kind may
have no agent: it holds the token, the resource list and the write mode
for the tools of a chat, and never receives or answers a message. The
GitHub kind declares it, so a person no longer makes a throwaway agent
only to store a token.
Without an agent the host refuses every setting that needs one:
listening, accepting senders, an allowlist, a notification chat,
talk-back channels, permissions, pairing and trigger approval. The
places that read the agent of a binding handle the empty value:
inbound routing, the polling loop, notifications, pairing, the capability
check (deny by default) and the grant switch. A kind that does not
declare the key still needs an agent on every binding.
The binding page makes the agent field optional for such a kind with
help text, and the list shows "Credentials only".
Assisted-by: Claude:claude-sonnet-5-5 go gofmt ginkgo node protoc swag
No release ever shipped add-ons, so there is no installed base on api 1.
The manifest must now declare api {"min": 2, "max": 2}; a manifest with
api 1, no api or a wider range is refused with a message that names the
range.
Every field that was gated on api 2 is now part of the contract, so the
Min*API constants and their gates are gone, and so are HostAPIMin and
the apiMin host field. Three older-manifest shims go with them: the
resource listing the host implied for one add-on, the legacyArgs hint
for arguments an older version of a tool took, and the tests that
checked the gates. All shipped manifests and the test fixtures declare
api 2.
Assisted-by: Claude:claude-sonnet-5-5 go test
A connection now has a write mode, chosen on the add-on page: off (the
default), propose (each change waits for the person to confirm) or auto
(a chat of the person makes it at once). The host enforces it for every
write tool of an add-on that holds a credential, before the add-on is
called, and holds the call to the repository list of the connection.
Host:
- Binding.WriteMode, stored in both stores and in the connector API
(write_mode). Absent means off, so existing bindings stay read only.
- A credentialed add-on may declare write tools. They name the resource
with the credential slot argument, never resourceId. A tool can set
approval "always", a ceiling that keeps a proposal even in auto.
- The proposal broker fetches the credential for the preview and again
for the apply, so it is never stored. A mode lowered between the
proposal and the confirmation refuses the apply. A proposal that
awaits a person cannot be confirmed by a chat turn.
- New capability name tools.write for the roles a connector kind
declares.
Add-on, tools (kind write): comment-issue, comment-pr, create-issue,
edit-issue (title, close or reopen), add-labels, review-comment-pr.
They preview plain facts, refuse a stale target, cap and screen the
text for secrets, and keep a receipt journal plus a hidden marker in the
text, so a change whose answer was lost is not sent twice.
Assisted-by: Claude:claude-sonnet-5-5 go gofmt ginkgo node
The previous commit was made on a stale base and so reverted work that
landed on master before it. This commit puts every file back to the
state of its parent's parent. The permission enforcement of the
previous commit stays.
Assisted-by: Claude:claude-sonnet-5-5 go
The capabilities, role grants and pairing that a connector binding
stores now decide what a sender can make the agent do.
Authorize is one pure function: the capability must be in the owner's
ceiling for the binding and the sender must be on the allowlist. A
sensitive capability then needs a paired sender; roles never count for
it. Any other capability needs a pairing or a role that the owner
granted and that the kind lists. The default is no.
Each message gets a grant for its sender. A message that joins a
running turn narrows it to what both senders may do. The tool builder
offers a gated tool only for a held capability, and the tool checks
again when the model calls it, so a call that gets through is refused
with the reason. Today this covers propose_change (memory and profile
kinds), revert_change, the trigger tools, and files sent to the bot. A
chat worker gets the grant with the start request.
The capability gate that the trigger features ask is now answered by
Authorize, and the application sets it. Other features can add a
global switch with AddCapabilitySwitch.
Every use records an allow or deny row (time, binding, sender IDs,
roles, capability, result; no text or codes). GET
/api/chats/connectors/{id}/access returns the effective permissions
per kind of sender and the latest rows, for an add-on settings page.
A binding saved before this change has no capabilities, so its senders
lose these features until the owner enables them.
Assisted-by: Claude:claude-sonnet-5-5 go swag
Add the github add-on: manifest with a credential slot, a read-only
tool set (code search, files, trees, issues, pull requests and diffs)
with size caps and untrusted-content framing, rate-limit mapping, a
connector route that checks the token, and a fake GitHub API for tests.
Assisted-by: Claude:claude-sonnet-5-5 [go]