Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion claude-for-msft-365-install/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "claude-for-msft-365-install",
"description": "Provision direct cloud access (Vertex AI, Bedrock, or LLM gateway) for the Claude Office add-in. Generates the customized add-in manifest, walks through Azure admin consent, and writes per-user config via Microsoft Graph extension attributes.",
"version": "0.1.8",
"version": "0.1.9",
"author": {
"name": "Anthropic",
"email": "support@anthropic.com"
Expand Down
11 changes: 11 additions & 0 deletions claude-for-msft-365-install/commands/bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,17 @@ layer.
"disabled_features": ["skills.authoring"]
```

### `available_models`

Model-picker override for this user — same semantics and entry forms as the
[manifest key](manifest.md#available_models). A JSON array of ids and/or
`{id, label}` objects; because it is an override, list every model the user
should keep.

```json
"available_models": [{ "id": "claude-opus-4-8", "label": "Opus 4.8" }, "claude-sonnet-5"]
```

### `access_policies`

Native JSON array of allow/deny statements — the per-user layer of the
Expand Down
21 changes: 21 additions & 0 deletions claude-for-msft-365-install/commands/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,27 @@ Unknown slugs are ignored (forward-compatible). Setting it here applies one
policy org-wide; per-user policy belongs in [bootstrap](bootstrap.md#disabled_features)
(JSON array) or extension attrs (comma-separated).

## available_models

`available_models` **overrides** the model picker — when set, users see exactly
the models listed, in the listed order, and nothing else. It replaces the
retired `disabled_models` / `additional_models` pair: because it is an
override, it must include every backend model users should keep, not just
additions or removals.

Two formats:

```bash
# comma-separated ids
available_models='claude-opus-4-8,claude-sonnet-5'

# JSON, when picker labels matter — an array of ids and/or {id, label} objects
available_models='[{"id":"claude-opus-4-8","label":"Opus 4.8"},"claude-sonnet-5"]'
```

Unset (or empty) means the picker is unchanged. Setting it here applies
org-wide; per-user policy belongs in [bootstrap](bootstrap.md#available_models).

## access_policies

`access_policies` is the IAM-shaped successor to `disabled_features` — a JSON
Expand Down
27 changes: 27 additions & 0 deletions claude-for-msft-365-install/scripts/build-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,33 @@ const KEYS = {
pattern: /^[\w.]+(,[\w.]+)*$/,
hint: "comma-separated feature slugs to lock for users, e.g. skills.authoring",
},
available_models: {
// Comma-separated model ids, or JSON: an array of ids and/or {id, label}
// objects (a lone object is single-entry shorthand). Mirrors the add-in's
// parseModelIdEntries leniency but warns where the runtime would silently drop.
pattern: /\S/,
hint: "override the model picker: comma-separated model ids, or JSON like [{\"id\":\"claude-opus-4-8\",\"label\":\"Opus 4.8\"}] — an OVERRIDE, list every model users should see",
validate: (v) => {
const t = v.trim();
if (!t.startsWith("[") && !t.startsWith("{")) {
return t.split(",").some((id) => !id.trim()) ? ["blank entry in comma-separated id list"] : [];
}
let parsed;
try {
parsed = JSON.parse(t);
} catch (e) {
throw new Error(`available_models is not valid JSON: ${e.message}`);
}
const arr = Array.isArray(parsed) ? parsed : [parsed];
return arr.flatMap((entry, i) => {
if (typeof entry === "string") return entry.trim() ? [] : [`entry[${i}]: blank id`];
if (typeof entry === "object" && entry !== null) {
return typeof entry.id === "string" && entry.id.trim() ? [] : [`entry[${i}]: missing string "id"`];
}
return [`entry[${i}]: expected an id string or {id, label} object`];
});
},
},
access_policies: {
pattern: /^\[.*\]$/s,
hint: "JSON array of policy statements — see commands/access-policies.md; e.g. [{\"effect\":\"deny\",\"action\":\"addin.access\",\"resource\":{...}}]",
Expand Down
Loading