@open-everywhere/create 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,7 +58,7 @@ prompts. The directory must be new or empty. A fresh clone of an empty repositor
58
58
  and it counts as empty: run `npx @open-everywhere/create .` inside it. The scaffold refuses a
59
59
  directory that holds anything else. Run inside an empty clone named `my-agent`,
60
60
  `npx @open-everywhere/create my-agent` would make `my-agent/my-agent/`, so it refuses and prints the
61
- `.` command instead. To nest on purpose, create the inner directory first. The app depends on the eight `@open-everywhere/*` libraries at
61
+ `.` command instead. To nest on purpose, create the inner directory first. The app depends on the nine `@open-everywhere/*` libraries at
62
62
  this CLI's own version — plus this package itself, as a dev dependency, for its `check` script — and
63
63
  on `eve` at the pin core declares; its `postinstall` applies the eve patch. Its roster mounts the launch surfaces: Slack, Notion and GitHub. The app carries `AGENTS.md`,
64
64
  a `.mcp.json` for the `open-everywhere-ops` MCP server and the `quickstart-open-everywhere` skill,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-everywhere/create",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "description": "npx scaffold and setup check for Open Everywhere — one step engine, reported by --check for an agent-led setup.",
@@ -46,8 +46,8 @@
46
46
  "test:env-pipe": "tsx scripts/env-pipe-test.ts"
47
47
  },
48
48
  "dependencies": {
49
- "@open-everywhere/core": "0.5.0",
50
- "@open-everywhere/provider-slack": "0.5.0",
49
+ "@open-everywhere/core": "0.6.0",
50
+ "@open-everywhere/provider-slack": "0.6.0",
51
51
  "tsx": "^4.23.9"
52
52
  },
53
53
  "devDependencies": {
package/src/scaffold.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  // THE SCAFFOLD — `npx @open-everywhere/create <dir>` copies the quickstart app (this package's
2
2
  // `template/` directory) into a new or empty `<dir>`, and then prints the next steps.
3
3
  //
4
- // The template is a minimal npm-consumer app: the eight `@open-everywhere/*` libraries and `eve`,
4
+ // The template is a minimal npm-consumer app: the nine `@open-everywhere/*` libraries and `eve`,
5
5
  // a roster of the launch surfaces (Slack, Notion, GitHub), and the agent config. Every
6
6
  // `@open-everywhere/*` dependency, `@open-everywhere/create` itself, and the versions in
7
7
  // `roster.lock.json` carry the {@link VERSION_PLACEHOLDER}. The scaffold replaces it with this
8
- // CLI's own version: all nine packages publish in lockstep, so this CLI's version IS the version
8
+ // CLI's own version: all ten packages publish in lockstep, so this CLI's version IS the version
9
9
  // of every library it installs.
10
10
  //
11
11
  // THREE PACKING RULES SHAPE THE TEMPLATE:
@@ -17,8 +17,10 @@ import {
17
17
  type Bundle,
18
18
  } from "@open-everywhere/core/agent/access/bundle.js";
19
19
  import { mcpServerBindings, mcpServerBundles } from "@open-everywhere/core/agent/connections/mcp-servers.js";
20
+ import { domainRuleBindings, domainRuleBundles } from "@open-everywhere/core/agent/access/domain-rules.js";
20
21
  import { loadGrantsOverlay } from "./grants.js";
21
22
  import { MCP_SERVERS } from "./mcp-servers.js";
23
+ import { DOMAIN_RULES } from "./domain-rules.js";
22
24
  import { PRE_APPROVAL_RULES } from "./pre-approval-rules.js";
23
25
  import { loadAgentsOverlay } from "../memory/config/agents-overlay.js";
24
26
  import { loadGroups } from "../identity/groups.js";
@@ -66,6 +68,10 @@ const bindings: Binding[] = [
66
68
  // every person's OWN DM (the built-in `oe:everyone` group, or the groups the entry names). Never a channel.
67
69
  bundles.push(...mcpServerBundles(MCP_SERVERS));
68
70
  bindings.push(...mcpServerBindings(MCP_SERVERS));
71
+ // The domain rules people asked for from approval cards and an admin merged (./domain-rules.ts, OPE-2456): each
72
+ // domain's rules in one bundle, bound at that domain's scope only.
73
+ bundles.push(...domainRuleBundles(DOMAIN_RULES));
74
+ bindings.push(...domainRuleBindings(DOMAIN_RULES));
69
75
 
70
76
  const overlay = loadGrantsOverlay();
71
77
  const agentsOverlay = loadAgentsOverlay();
@@ -0,0 +1,18 @@
1
+ // Domain rules — the acts one domain's people asked to allow without a card, merged by an admin.
2
+ //
3
+ // A person in a domain room can choose "Approve, and allow things like this" on an approval card. After they confirm
4
+ // the rule in plain words, the agent opens a pull request that adds one line here (or widens the line for the same
5
+ // tool and kind of action). Nothing applies until an admin merges it. The pull request names who asked, from which
6
+ // card, and quotes the act.
7
+ //
8
+ // Each line is ONE JSON entry: the domain, a stable id, the rule the approval judge reads, and the structured policy
9
+ // the rule was written from. A rule states policy — the tool, the kind of action, the kind of object — and never one
10
+ // object: config load refuses a rule that names a URL, an id or a numbered item. Delete a line to remove its rule.
11
+ // Keep one entry per line, with a trailing comma: the agent's pull requests edit this file line by line.
12
+ //
13
+ // The full reference is docs/how-it-works/pre-approval-rules.md in the Open Everywhere repository.
14
+
15
+ import { defineDomainRules } from "@open-everywhere/core/agent/access/domain-rules.js";
16
+
17
+ export const DOMAIN_RULES = defineDomainRules([
18
+ ]);
@@ -22,6 +22,7 @@ import "./lib/register-adapters.js";
22
22
  import "@open-everywhere/core/agent/access/eve-patch-probe-boot.js";
23
23
  import { gatewayModelResolver } from "@open-everywhere/adapters/agent/model/gateway.js";
24
24
  import { registerGatewayDreamJudge, registerGatewayFailureFacetJudge } from "@open-everywhere/adapters/agent/model/dream-judge.js";
25
+ import { registerGatewayMeetingModels } from "@open-everywhere/adapters/agent/model/meeting-gateway.js";
25
26
  import { registerGatewayApprovalJudge } from "@open-everywhere/adapters/agent/model/approval-judge.js";
26
27
  import { registerGatewayImageDescriber } from "@open-everywhere/adapters/agent/model/gateway-vision.js";
27
28
  import { isModelUsable } from "@open-everywhere/core/agent/model/policy.js";
@@ -29,6 +30,7 @@ import {
29
30
  JUDGE_MODEL,
30
31
  PRIMARY_MODEL,
31
32
  PRIMARY_MODEL_CONTEXT_WINDOW_TOKENS,
33
+ TRANSCRIPTION_ROLE,
32
34
  UTILITY_MODEL,
33
35
  VISION_MODEL,
34
36
  } from "./model/models.js";
@@ -52,6 +54,11 @@ const COMPACTION_THRESHOLD_TOKENS = compactionThresholdTokens(PRIMARY_MODEL_CONT
52
54
  // The background judges: memory distillation, failure facets and the auto-approval judge.
53
55
  registerGatewayDreamJudge({ id: UTILITY_MODEL, gateway: GATEWAY_DEFAULTS });
54
56
  registerGatewayFailureFacetJudge({ id: UTILITY_MODEL, gateway: GATEWAY_DEFAULTS });
57
+
58
+ // The meeting bot's model calls (OPE-2459): the `gateway` transcription route, and the tool-less recap
59
+ // completion on the same `utility` route as the dream judge. Inert until agent/meetings/policy.ts enables
60
+ // meetings; without this line the `gateway` route is unregistered and `meeting_join` refuses before its card.
61
+ registerGatewayMeetingModels({ id: UTILITY_MODEL, gateway: GATEWAY_DEFAULTS }, TRANSCRIPTION_ROLE);
55
62
  registerGatewayApprovalJudge({ id: JUDGE_MODEL, gateway: GATEWAY_DEFAULTS });
56
63
 
57
64
  // The image describer. Fail at boot if the org model policy forbids the vision model, rather than
@@ -0,0 +1,40 @@
1
+ // THIS DEPLOYMENT'S EMAIL POLICY — the agent's own email address (OPE-2440). Config-as-code: a change here is a
2
+ // reviewed pull request. The schema and its validation are `@open-everywhere/core/agent/email/policy.js`; the
3
+ // operator guide is the "Email" surface page of the manual (`read_docs`).
4
+ //
5
+ // Each field is a decision about who may write to the agent:
6
+ // enabled — the master switch. Off refuses every inbound mail.
7
+ // transport — the registered transport that carries the mail ("agentmail" or "agentmail-eu" ship).
8
+ // orgDomains — the mail domains this org controls. Every inbox must sit on one of them (white-label: OE
9
+ // never hands out an address on a domain it runs), and an authenticated sender on one of
10
+ // them binds internal. Everyone else binds external.
11
+ // inboxes — `room`: mail wakes the domain whose `reach` lists `email/<domain>/<local part>`.
12
+ // `personal`: mail from a person declared in agent/identity/principals.ts (ids.email) wakes
13
+ // that person's own DM seat.
14
+ // allowedSenders — who may write to a room inbox: exact addresses or "*@domain". Add one by asking the agent
15
+ // (an approval card opens a pull request to agent/email/senders.ts) or by hand here.
16
+ // maxRecipients — the most addresses one reply may go to (a reply-all is limited to people allowed anyway).
17
+ //
18
+ // 🔴 NOTHING HERE IS A SECRET. The transport's API key and webhook secret live in the secret store
19
+ // (`oe secret set AGENTMAIL_API_KEY`, `oe secret set AGENTMAIL_WEBHOOK_SECRET`), never in this file.
20
+
21
+ import { DEFAULT_EMAIL_POLICY, registerEmailPolicy, type EmailPolicy } from "@open-everywhere/core/agent/email/policy.js";
22
+ import { EMAIL_SENDERS } from "./senders.js";
23
+
24
+ const emailPolicy: EmailPolicy = {
25
+ ...DEFAULT_EMAIL_POLICY,
26
+ enabled: false,
27
+ transport: "agentmail",
28
+ orgDomains: [
29
+ // Your own mail domain(s). Example, inert while `enabled` is false:
30
+ // "acme.com",
31
+ ],
32
+ inboxes: [
33
+ // Example inboxes, inert while `enabled` is false. Put the room inbox's surface key
34
+ // ("email/agent.acme.com/launch") in the launch domain's `reach`.
35
+ // { address: "launch@agent.acme.com", kind: "room", allowedSenders: ["*@acme.com"], why: "The launch team's shared inbox." },
36
+ // { address: "oe@agent.acme.com", kind: "personal", allowedSenders: [], why: "Each person's own chief of staff by email." },
37
+ ],
38
+ };
39
+
40
+ registerEmailPolicy(emailPolicy, EMAIL_SENDERS);
@@ -0,0 +1,14 @@
1
+ // Email senders — the allowed senders people asked to add to a room inbox, merged by an admin (OPE-2440).
2
+ //
3
+ // A person asks the agent to let someone email a room inbox. The agent posts an approval card; a tap opens a pull
4
+ // request that adds one line here. Nothing applies until an admin merges it. The pull request names who asked and
5
+ // who approved.
6
+ //
7
+ // Each line is ONE JSON entry: the room inbox, the sender (an exact address or "*@domain"), why, and the
8
+ // provenance. Delete a line to remove the sender. Keep one entry per line, with a trailing comma: the agent's pull
9
+ // requests edit this file line by line. The inbox must be a room inbox declared in ./policy.ts, or the boot fails.
10
+
11
+ import { defineEmailSenders } from "@open-everywhere/core/agent/email/policy.js";
12
+
13
+ export const EMAIL_SENDERS = defineEmailSenders([
14
+ ]);
@@ -62,6 +62,18 @@ import "../identity/surfaces.js";
62
62
  // `agent/sandbox/sandbox.ts` through this module's import and nothing else. Drop this import and the
63
63
  // declaration is empty at bake time, so the capability silently refuses to arm.
64
64
  import "../access/browser-hosts.js";
65
+ // Side effect: register this deployment's MEETING POLICY (agent/meetings/policy.ts, OPE-2459) — which
66
+ // meeting hosts the bot may join, the retention windows, the bot's box and the transcription route. Off
67
+ // unless the file enables it; a bad policy fails the boot rather than arming a bot nobody reviewed.
68
+ import "../meetings/policy.js";
69
+ // Side effect: register this deployment's EMAIL POLICY (agent/email/policy.ts, OPE-2440) — the agent's own
70
+ // inboxes, who may write to each, and how wide a reply may go. Off unless the file enables it; a bad policy
71
+ // (an inbox off the org's domains, a bare wildcard sender, a sender line naming no room inbox) fails the boot.
72
+ import "../email/policy.js";
73
+ // Side effect: register this deployment's PERSONAL BROWSER POLICY (agent/personal-browser/policy.ts, OPE-2441) —
74
+ // whether a person may have their own browser that keeps their logins, its box, and how long its sessions,
75
+ // logins, take-overs and act approvals last. Off unless the file enables it; a bad policy fails the boot.
76
+ import "../personal-browser/policy.js";
65
77
  // Side effect: register the operator's per-AUTHOR trust register (identity/author-trust.ts) — the
66
78
  // AUTHORITY plane, the sibling of the surfaces AUDIENCE plane above. Self-registering, and it must
67
79
  // come AFTER the groups module loads (it expands `{ group: … }` members through loadGroups at
@@ -0,0 +1,44 @@
1
+ // THIS DEPLOYMENT'S MEETING POLICY — OE's own meeting bot (OPE-2459). Config-as-code: a change here is a
2
+ // reviewed pull request. The schema and its validation are `@open-everywhere/core/agent/meetings/policy.js`;
3
+ // the operator guide is the "Meetings" page of the manual (`read_docs`).
4
+ //
5
+ // Each field is a decision about other people's meetings:
6
+ // enabled — the master switch. Off refuses every "join this meeting" ask.
7
+ // hosts — the meeting hosts the bot may join. A Teams rule lists the organiser tenants OE may
8
+ // join; the tenant id is read from the link and is not verified with Microsoft, so it
9
+ // refuses an outside link pasted as it is, not an edited one. A Meet link names no
10
+ // organiser, so a Meet rule must accept that in writing (`owner: "unverifiable"`).
11
+ // retention — how long OE keeps audio (0 = never stored) and the transcript.
12
+ // box — the bot image and its size. It runs on this deployment's own sandbox backend.
13
+ // transcription — `gateway` (audio through this deployment's AI Gateway) or `box` (text only).
14
+ // native — recaps from the platform's OWN transcript (Teams, Meet, Zoom), no bot (OPE-2471). Each
15
+ // platform block names the ORGANISATION's credential: identifiers here, the secret's value
16
+ // in the db credential store (`oe secret set <name>`). Off until OPE-2461 and OPE-2464 land.
17
+ //
18
+ // 🔴 NOTHING HERE IS A SECRET. A tenant id, a client id and a secret's NAME are identifiers, not credentials.
19
+ //
20
+ // To turn meetings on: build and publish the bot image (the manual's Meetings page says how), set
21
+ // `box.image`, add your host rules, and set `enabled: true`. Until OPE-2461 (per-row expiry for the shared
22
+ // store) and OPE-2464 (untrusted provenance for the recap post) land, `enabled: true` is REFUSED: the boot
23
+ // fails and names both tickets.
24
+
25
+ import { DEFAULT_MEETING_POLICY, registerMeetingPolicy, type MeetingPolicy } from "@open-everywhere/core/agent/meetings/policy.js";
26
+
27
+ const meetingPolicy: MeetingPolicy = {
28
+ ...DEFAULT_MEETING_POLICY,
29
+ enabled: false,
30
+ hosts: [
31
+ // Example rules, inert while `enabled` is false. Replace the tenant id with your own.
32
+ // { platform: "meet", host: "meet.google.com", owner: "unverifiable", why: "Our team meets on Google Meet." },
33
+ // { platform: "teams", host: "teams.microsoft.com", tenants: ["00000000-0000-0000-0000-000000000000"], why: "Our own Teams tenant only." },
34
+ ],
35
+ native: {
36
+ ...DEFAULT_MEETING_POLICY.native,
37
+ // Example blocks, inert while `native.enabled` is false. See the manual's Meetings page for what each admin grants.
38
+ // teams: { tenants: ["00000000-0000-0000-0000-000000000000"], clientId: "00000000-0000-0000-0000-000000000000", clientSecretRef: "TEAMS_TRANSCRIPT_SECRET", why: "Our own Teams meetings." },
39
+ // meet: { domains: ["example.org"], serviceAccountKeyRef: "MEET_TRANSCRIPT_KEY", why: "Our own Workspace meetings." },
40
+ // zoom: { accountId: "<Zoom account id>", clientId: "<S2S app client id>", clientSecretRef: "ZOOM_TRANSCRIPT_SECRET", why: "Our own Zoom account." },
41
+ },
42
+ };
43
+
44
+ registerMeetingPolicy(meetingPolicy);
@@ -8,7 +8,7 @@ import {
8
8
  } from "@open-everywhere/core/agent/model/default-model.js";
9
9
  import { getSettings } from "@open-everywhere/core/agent/settings/settings.js";
10
10
  import { SETTINGS_OVERRIDES } from "../settings/settings.js";
11
- import { resolveStack, type ModelRole, type ModelRoleSpec, type ModelStack } from "./stacks.js";
11
+ import { resolveStack, resolveTranscription, type ModelRole, type ModelRoleSpec, type ModelStack } from "./stacks.js";
12
12
 
13
13
  export type { ModelRoleSpec, ModelStack } from "./stacks.js";
14
14
 
@@ -31,6 +31,8 @@ export const MODELS = {
31
31
 
32
32
  /** The alias of the stack this process resolved — for `/oe status`. */
33
33
  export const MODEL_STACK = STACK_ALIAS;
34
+ /** The meeting bot's speech-to-text role: a primary and a fallback route (stacks.ts TRANSCRIPTION). */
35
+ export const TRANSCRIPTION_ROLE = resolveTranscription(STACK_ALIAS);
34
36
 
35
37
  export const PRIMARY_MODEL = MODELS.primary.id;
36
38
  export const UTILITY_MODEL = MODELS.utility.id;
@@ -12,6 +12,7 @@
12
12
  // agent/spend/model-pricing.ts, or a USD spend cap cannot see its cost.
13
13
 
14
14
  import type { ModelTier } from "@open-everywhere/core/agent/memory/domain.js";
15
+ import type { TranscriptionRoleSpec } from "@open-everywhere/adapters/agent/model/transcription-routes.js";
15
16
 
16
17
  export type ModelRole = "primary" | "utility" | "vision" | "supervisor" | "judge";
17
18
 
@@ -35,7 +36,7 @@ export const STACKS = {
35
36
  "american-closed": {
36
37
  primary: { id: "openai/gpt-6-luna", tier: "high", contextWindowTokens: 1_050_000 },
37
38
  utility: { id: "openai/gpt-6-luna", tier: "low", contextWindowTokens: 1_050_000 },
38
- vision: { id: "google/gemini-3.7-flash", tier: "low", contextWindowTokens: 1_000_000 },
39
+ vision: { id: "google/gemini-3.8-flash", tier: "low", contextWindowTokens: 1_000_000 },
39
40
  supervisor: { id: "openai/gpt-6-luna", tier: "low", contextWindowTokens: 1_050_000 },
40
41
  judge: { id: "openai/gpt-6-luna", tier: "low", contextWindowTokens: 1_050_000 },
41
42
  },
@@ -73,3 +74,33 @@ export function resolveStack(alias: string, overrides: StackOverrides = {}): Mod
73
74
  }
74
75
  return out;
75
76
  }
77
+
78
+ // Speech to text for the meeting bot: a primary and a fallback route per stack, on two different providers, so
79
+ // one provider outage falls through to the other. A route names its transport too: the AI Gateway, DeepInfra
80
+ // (key: `oe secret set DEEPINFRA_API_KEY`), or your own OpenAI-compatible speech server. These defaults are
81
+ // pending a bake-off (`npm run bakeoff:stt` in the Open Everywhere repository).
82
+ export const TRANSCRIPTION = {
83
+ "chinese-open-weights": {
84
+ primary: { via: "deepinfra", id: "Qwen/Qwen3-ASR-1.7B" },
85
+ fallback: { via: "self-hosted", id: "Qwen/Qwen3-ASR-1.7B", baseUrl: "http://qwen3-asr:8000/v1" },
86
+ },
87
+ "american-closed": {
88
+ primary: { via: "gateway", id: "microsoft/mai-transcribe-2" },
89
+ fallback: { via: "gateway", id: "spacexai/grok-stt" },
90
+ },
91
+ } as const satisfies Record<StackAlias, TranscriptionRoleSpec>;
92
+
93
+ /** Fully local: your own speech server only. For a Docker deployment with no cloud model. */
94
+ export const LOCAL_TRANSCRIPTION = {
95
+ primary: { via: "self-hosted", id: "Qwen/Qwen3-ASR-1.7B", baseUrl: "http://qwen3-asr:8000/v1" },
96
+ } as const satisfies TranscriptionRoleSpec;
97
+
98
+ /** `stack` follows `models.stack`; `local` uses LOCAL_TRANSCRIPTION. */
99
+ export const TRANSCRIPTION_PLACEMENT: "stack" | "local" = "stack";
100
+
101
+ /** The transcription role for `alias`. Throws on an unknown alias. */
102
+ export function resolveTranscription(alias: string, placement: "stack" | "local" = TRANSCRIPTION_PLACEMENT): TranscriptionRoleSpec {
103
+ if (placement === "local") return LOCAL_TRANSCRIPTION;
104
+ if (!isStackAlias(alias)) throw new Error(`open-everywhere: unknown model stack "${alias}" — no transcription role`);
105
+ return TRANSCRIPTION[alias];
106
+ }
@@ -0,0 +1,33 @@
1
+ // THIS DEPLOYMENT'S PERSONAL BROWSER POLICY — each person's own browser, which keeps their logins (OPE-2441).
2
+ // Config-as-code: a change here is a reviewed pull request. The schema and its validation are
3
+ // `@open-everywhere/core/agent/personal-browser/policy.js`; the operator guide is the "Personal browser" page
4
+ // of the manual (`read_docs`).
5
+ //
6
+ // Each field is a decision about a person's signed-in accounts:
7
+ // enabled — the master switch. Off refuses every use.
8
+ // box — the browser image and its size. It runs on this deployment's own sandbox backend: a
9
+ // persistent Vercel Sandbox per person, or a docker container on a named volume.
10
+ // `dockerNetwork` (docker only) is the network the app and the box share.
11
+ // sessionMinutes — the hard cap on one live session of the box.
12
+ // idleMinutes — the box stops after this long with nobody using or watching it. Logins stay.
13
+ // keepLoginsDays — how long the profile (the logins) survives with no use.
14
+ // takeoverMinutes — the longest a person holds the controls before they return to the agent.
15
+ // actGrantMinutes — how long one "let the agent click and type on this site" approval lasts.
16
+ //
17
+ // WHERE THE BROWSER MAY GO is not declared here: it reaches exactly the hosts the person's DM's egress
18
+ // declaration admits (agent/access — bundles and network access), the same firewall every other call uses.
19
+ //
20
+ // 🔴 NOTHING HERE IS A SECRET.
21
+ //
22
+ // To turn it on: build and publish the browser image (the manual's Personal browser page says how), set
23
+ // `box.image`, and set `enabled: true`. The watch page also needs the page signing key
24
+ // (OE_INTAKE_PAGE_SIGNING_KEY) and a public URL, which the credential intake page already uses.
25
+
26
+ import { DEFAULT_PERSONAL_BROWSER_POLICY, registerPersonalBrowserPolicy, type PersonalBrowserPolicy } from "@open-everywhere/core/agent/personal-browser/policy.js";
27
+
28
+ const personalBrowserPolicy: PersonalBrowserPolicy = {
29
+ ...DEFAULT_PERSONAL_BROWSER_POLICY,
30
+ enabled: false,
31
+ };
32
+
33
+ registerPersonalBrowserPolicy(personalBrowserPolicy);
@@ -15,7 +15,7 @@ const pricing: ModelPricingTable = defineModelPricing({
15
15
  // chinese-open-weights: vision.
16
16
  "alibaba/qwen3-vl-instruct": { inPerMtok: 0.2, outPerMtok: 0.88 },
17
17
  // american-closed: vision.
18
- "google/gemini-3.7-flash": { inPerMtok: 0.75, outPerMtok: 3.75 },
18
+ "google/gemini-3.8-flash": { inPerMtok: 0.75, outPerMtok: 3.75 },
19
19
  });
20
20
 
21
21
  assertModelPricingValid(pricing);
@@ -37,7 +37,7 @@ npm view @open-everywhere/core version
37
37
  **Read the installed one, not the pin.** `oe upgrade` writes the pins before it installs, so an
38
38
  upgrade that stopped part way leaves a manifest that names a version the app is not running.
39
39
 
40
- The nine packages publish in lockstep, so one version answers for all of them. Agree the target
40
+ The ten packages publish in lockstep, so one version answers for all of them. Agree the target
41
41
  with the user before you go on. Taking the latest is the normal choice.
42
42
 
43
43
  ## 2. Read the notes between the two versions
@@ -33,6 +33,7 @@ node_modules/
33
33
  /agent/skills/
34
34
  /agent/connections/
35
35
  /agent/lib/providers.generated.ts
36
+ /agent/lib/app-code-fingerprint.generated.ts
36
37
 
37
38
  # Misc
38
39
  *.log
@@ -40,3 +41,6 @@ node_modules/
40
41
  *.tsbuildinfo
41
42
  *.pem
42
43
  *.key
44
+
45
+ # A built Teams app package (`surface_app_package`): rebuilt from config, never committed.
46
+ teams-app/*.zip
@@ -26,6 +26,7 @@
26
26
  "@open-everywhere/adapters": "{{OE_VERSION}}",
27
27
  "@open-everywhere/core": "{{OE_VERSION}}",
28
28
  "@open-everywhere/provider-discord": "{{OE_VERSION}}",
29
+ "@open-everywhere/provider-email": "{{OE_VERSION}}",
29
30
  "@open-everywhere/provider-github": "{{OE_VERSION}}",
30
31
  "@open-everywhere/provider-linear": "{{OE_VERSION}}",
31
32
  "@open-everywhere/provider-notion": "{{OE_VERSION}}",
@@ -29,8 +29,8 @@ export default defineRoster({
29
29
  core: true,
30
30
  adapters: true,
31
31
 
32
- // One provider bundle per surface. Add a line to add a surface (`discord`, `teams` and `linear`
33
- // are installed too), then `npx oe build --accept`.
32
+ // One provider bundle per surface. Add a line to add a surface (`discord`, `teams`, `linear` and
33
+ // `email` are installed too), then `npx oe build --accept`.
34
34
  providers: {
35
35
  slack: true,
36
36
  notion: true,
@@ -22,8 +22,10 @@
22
22
  "channel/control-mcp": "mounted",
23
23
  "channel/control-read": "mounted",
24
24
  "channel/credential-intake-page": "mounted",
25
+ "channel/meeting-callback": "mounted",
25
26
  "channel/oe-oauth-callback": "mounted",
26
27
  "channel/oe-status": "mounted",
28
+ "channel/personal-browser": "mounted",
27
29
  "channel/policy-pages": "mounted",
28
30
  "channel/test-wake": "mounted",
29
31
  "channel/transcript-relay": "mounted",
@@ -67,11 +69,15 @@
67
69
  "schedule/directory-sync": "mounted",
68
70
  "schedule/dispatch": "mounted",
69
71
  "schedule/dream-mode3": "mounted",
72
+ "schedule/meeting-sweep": "mounted",
73
+ "schedule/personal-browser-sweep": "mounted",
70
74
  "schedule/tidy": "mounted",
71
75
  "skill/scoped": "mounted",
72
76
  "tool/add_label": "mounted",
73
77
  "tool/add_routine_rule": "mounted",
74
78
  "tool/agent_version": "mounted",
79
+ "tool/answer_domain_question": "mounted",
80
+ "tool/ask_domain": "mounted",
75
81
  "tool/ask_question": "mounted",
76
82
  "tool/ask_room": "mounted",
77
83
  "tool/assign": "mounted",
@@ -111,15 +117,21 @@
111
117
  "tool/list_routines": "mounted",
112
118
  "tool/list_skills": "mounted",
113
119
  "tool/list_webhooks": "mounted",
120
+ "tool/meeting_join": "mounted",
121
+ "tool/meeting_leave": "mounted",
122
+ "tool/meeting_recap": "mounted",
114
123
  "tool/memory_admin_list": "mounted",
115
124
  "tool/memory_admin_read": "mounted",
116
125
  "tool/message_thread_seat": "mounted",
126
+ "tool/my_browser": "mounted",
127
+ "tool/my_browser_handoff": "mounted",
117
128
  "tool/no_reply": "mounted",
118
129
  "tool/open_pull_request": "mounted",
119
130
  "tool/permission_fit_report": "mounted",
120
131
  "tool/post_file": "mounted",
121
132
  "tool/post_message": "mounted",
122
133
  "tool/post_pr_walkthrough": "mounted",
134
+ "tool/propose_email_sender": "mounted",
123
135
  "tool/propose_mcp_server": "mounted",
124
136
  "tool/purge_memory": "mounted",
125
137
  "tool/query_analytics": "mounted",
@@ -3,9 +3,11 @@ agent/channels/control-mcp.ts mounted @open-everywhere/core
3
3
  agent/channels/control-read.ts mounted @open-everywhere/core
4
4
  agent/channels/credential-intake-page.ts mounted @open-everywhere/core
5
5
  agent/channels/github.ts mounted @open-everywhere/provider-github
6
+ agent/channels/meeting-callback.ts mounted @open-everywhere/core
6
7
  agent/channels/notion.ts mounted @open-everywhere/provider-notion
7
8
  agent/channels/oe-oauth-callback.ts mounted @open-everywhere/core
8
9
  agent/channels/oe-status.ts mounted @open-everywhere/core
10
+ agent/channels/personal-browser.ts mounted @open-everywhere/core
9
11
  agent/channels/policy-pages.ts mounted @open-everywhere/core
10
12
  agent/channels/slack-commands.ts mounted @open-everywhere/provider-slack
11
13
  agent/channels/slack-setup-page.ts mounted @open-everywhere/provider-slack
@@ -54,12 +56,16 @@ agent/schedules/audit-export.ts mounted @open-everywhere/core
54
56
  agent/schedules/directory-sync.ts mounted @open-everywhere/core
55
57
  agent/schedules/dispatch.ts mounted @open-everywhere/core
56
58
  agent/schedules/dream-mode3.ts mounted @open-everywhere/core
59
+ agent/schedules/meeting-sweep.ts mounted @open-everywhere/core
57
60
  agent/schedules/notion-ingress.ts mounted @open-everywhere/provider-notion
61
+ agent/schedules/personal-browser-sweep.ts mounted @open-everywhere/core
58
62
  agent/schedules/tidy.ts mounted @open-everywhere/core
59
63
  agent/skills/scoped.ts mounted @open-everywhere/core
60
64
  agent/tools/add_label.ts mounted @open-everywhere/core
61
65
  agent/tools/add_routine_rule.ts mounted @open-everywhere/core
62
66
  agent/tools/agent_version.ts mounted @open-everywhere/core
67
+ agent/tools/answer_domain_question.ts mounted @open-everywhere/core
68
+ agent/tools/ask_domain.ts mounted @open-everywhere/core
63
69
  agent/tools/ask_question.ts mounted @open-everywhere/core
64
70
  agent/tools/ask_room.ts mounted @open-everywhere/core
65
71
  agent/tools/assign.ts mounted @open-everywhere/core
@@ -101,9 +107,14 @@ agent/tools/list_repos.ts mounted @open-everywhere/core
101
107
  agent/tools/list_routines.ts mounted @open-everywhere/core
102
108
  agent/tools/list_skills.ts mounted @open-everywhere/core
103
109
  agent/tools/list_webhooks.ts mounted @open-everywhere/core
110
+ agent/tools/meeting_join.ts mounted @open-everywhere/core
111
+ agent/tools/meeting_leave.ts mounted @open-everywhere/core
112
+ agent/tools/meeting_recap.ts mounted @open-everywhere/core
104
113
  agent/tools/memory_admin_list.ts mounted @open-everywhere/core
105
114
  agent/tools/memory_admin_read.ts mounted @open-everywhere/core
106
115
  agent/tools/message_thread_seat.ts mounted @open-everywhere/core
116
+ agent/tools/my_browser_handoff.ts mounted @open-everywhere/core
117
+ agent/tools/my_browser.ts mounted @open-everywhere/core
107
118
  agent/tools/no_reply.ts mounted @open-everywhere/core
108
119
  agent/tools/notion_search.ts mounted @open-everywhere/provider-notion
109
120
  agent/tools/open_pull_request.ts mounted @open-everywhere/core
@@ -111,6 +122,7 @@ agent/tools/permission_fit_report.ts mounted @open-everywhere/core
111
122
  agent/tools/post_file.ts mounted @open-everywhere/core
112
123
  agent/tools/post_message.ts mounted @open-everywhere/core
113
124
  agent/tools/post_pr_walkthrough.ts mounted @open-everywhere/core
125
+ agent/tools/propose_email_sender.ts mounted @open-everywhere/core
114
126
  agent/tools/propose_mcp_server.ts mounted @open-everywhere/core
115
127
  agent/tools/purge_memory.ts mounted @open-everywhere/core
116
128
  agent/tools/query_analytics.ts mounted @open-everywhere/core
@@ -47,5 +47,5 @@ registerSurfaceTrustPreflight();
47
47
  const server = buildOpsServer();
48
48
  await server.connect(new StdioServerTransport());
49
49
  process.stderr.write(
50
- "open-everywhere-ops MCP server ready on stdio (preflight · surface_manifest · scaffold_env · scaffold_credential_key · secret_set/list/rm)\n",
50
+ "open-everywhere-ops MCP server ready on stdio (preflight · surface_manifest · surface_app_package · scaffold_env · scaffold_credential_key · secret_set/list/rm)\n",
51
51
  );