@open-everywhere/create 0.4.0 → 0.5.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/package.json +3 -3
- package/template/agent/access/a2a-agents.ts +44 -0
- package/template/agent/access/access-requests.ts +3 -0
- package/template/agent/access/mcp-servers.ts +17 -0
- package/template/agent/instructions.md +4 -0
- package/template/agent/lib/register-config.ts +8 -0
- package/template/agent/memory/config/domains/index.ts +6 -0
- package/template/agent/webhooks/hooks.ts +5 -5
- package/template/roster.lock.json +6 -0
- package/template/scripts/goldens/roster-plan.txt +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-everywhere/create",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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.
|
|
50
|
-
"@open-everywhere/provider-slack": "0.
|
|
49
|
+
"@open-everywhere/core": "0.5.0",
|
|
50
|
+
"@open-everywhere/provider-slack": "0.5.0",
|
|
51
51
|
"tsx": "^4.23.9"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// The A2A AGENTS this app declares (OPE-2425) — config-as-code, changed by pull request only.
|
|
2
|
+
//
|
|
3
|
+
// MCP servers (./mcp-servers.ts) give the agent TOOLS AND DATA. A2A agents give it OTHER AGENTS: a
|
|
4
|
+
// focused enterprise agent — an Agentforce, ServiceNow, Workday or Copilot Studio agent — that takes a
|
|
5
|
+
// whole task in plain language and reports back. Each entry here is one such agent:
|
|
6
|
+
// • The agent reads the entry's published AGENT CARD and reaches ONLY the card URL's origin (scheme,
|
|
7
|
+
// host and port). A card that names an endpoint anywhere else is refused.
|
|
8
|
+
// • `delegate_to_agent` sends it a task. Every delegation takes an approval first: a member's click on
|
|
9
|
+
// a card that shows the agent, its host and the exact task text, or a pre-approval rule or the
|
|
10
|
+
// approval judge. The task goes out with the asker's identity attached
|
|
11
|
+
// (platform, workspace and their verified id) in the message metadata, with the person who approved
|
|
12
|
+
// it, or the rule that lifted it.
|
|
13
|
+
// • What the agent answers is UNTRUSTED content: it is fenced like any connector result, and it taints
|
|
14
|
+
// the turn that reads it.
|
|
15
|
+
//
|
|
16
|
+
// Only an INTERNAL room may delegate: a shared (Slack Connect), public or guest room is refused, and so
|
|
17
|
+
// is a request a guest or external account took part in. `domains` narrows it further.
|
|
18
|
+
//
|
|
19
|
+
// A person cannot add an agent: a name that is not in this list is refused. No secret goes in this
|
|
20
|
+
// file — an agent that needs a token names its credential-store REF (`npx oe secret set <ref>`).
|
|
21
|
+
// See docs/extending/a2a-agents.md.
|
|
22
|
+
|
|
23
|
+
import { defineA2aAgents } from "@open-everywhere/core/agent/a2a/agents.js";
|
|
24
|
+
|
|
25
|
+
export const A2A_AGENTS = defineA2aAgents([
|
|
26
|
+
// Example — an agent with a public card and no credential:
|
|
27
|
+
//
|
|
28
|
+
// {
|
|
29
|
+
// name: "it-helpdesk",
|
|
30
|
+
// cardUrl: "https://<the vendor's agent host>/.well-known/agent-card.json",
|
|
31
|
+
// description: "The IT helpdesk agent: opens, reads and updates IT tickets for a person.",
|
|
32
|
+
// },
|
|
33
|
+
//
|
|
34
|
+
// Example — an agent that takes a bearer token. Store the token with `npx oe secret set <ref>` and
|
|
35
|
+
// name the REF here, never the value:
|
|
36
|
+
//
|
|
37
|
+
// {
|
|
38
|
+
// name: "hr-agent",
|
|
39
|
+
// cardUrl: "https://agents.hr.example/.well-known/agent-card.json",
|
|
40
|
+
// description: "The HR agent: answers questions about leave, payroll dates and benefits.",
|
|
41
|
+
// auth: { scheme: "bearer", secretRef: "db:a2a:hr-agent-token" },
|
|
42
|
+
// domains: ["people-ops"], // optional: only conversations in these memory domains may use it
|
|
43
|
+
// },
|
|
44
|
+
]);
|
|
@@ -30,6 +30,7 @@ import { emptyAgentsFile } from "@open-everywhere/core/agent/memory/agents-codem
|
|
|
30
30
|
import { loadBaseBundles, loadBaseBindings } from "./bundles.js";
|
|
31
31
|
import { loadBaseConnectorCredentials } from "./connector-credentials.js";
|
|
32
32
|
import { loadBaseWebhooks } from "../webhooks/hooks.js";
|
|
33
|
+
import { MCP_SERVERS } from "./mcp-servers.js";
|
|
33
34
|
import { loadBaseDomains, loadBaseSilos, loadDomains } from "../memory/config/domains.js";
|
|
34
35
|
import { loadGroups } from "../identity/groups.js";
|
|
35
36
|
|
|
@@ -61,6 +62,8 @@ export function loadAccessRequests(): AccessRequestsConfig | null {
|
|
|
61
62
|
// baseline a candidate overlay is validated against before any PR opens.
|
|
62
63
|
hooksPath: process.env.OE_WEBHOOK_HOOKS_PATH || undefined,
|
|
63
64
|
baseWebhooks: loadBaseWebhooks,
|
|
65
|
+
// The declared MCP servers, so `propose_mcp_server` validates a candidate entry against them (OPE-2420).
|
|
66
|
+
baseMcpServers: () => MCP_SERVERS,
|
|
64
67
|
// The `create_agent` PR path (create_agent flow, increment 2) rides this SAME config repo, branch
|
|
65
68
|
// and bot credential — only the machine-written file differs (the agents overlay). `baseAgents` is
|
|
66
69
|
// the code-declared agents baseline (empty — agents live only in the overlay); `baseDomains` /
|
|
@@ -16,10 +16,23 @@
|
|
|
16
16
|
// which needs no client id and no secret. Only a vendor WITHOUT dynamic registration takes a static
|
|
17
17
|
// client, and then this file names the secret's credential-store REF, never its value.
|
|
18
18
|
// See docs/extending/connectors.md#declare-an-mcp-server-in-your-app.
|
|
19
|
+
//
|
|
20
|
+
// "SEARCH SLACK AS YOU" (OPE-2421) is a built-in entry: `slackAsYou({ clientId })` mounts Slack's own MCP
|
|
21
|
+
// server on each person's own Slack sign-in, in their Slack DM only. The agent answers with the bot first and
|
|
22
|
+
// offers the person's connection only when the bot cannot see what was asked; every post as the person takes a
|
|
23
|
+
// card. It reuses the org's own Slack app: name its public Client ID here, and store its Client Secret with
|
|
24
|
+
// `npx oe secret set db:slack:oauth-client-secret`. The Slack app also needs the MCP toggle (its Agents section)
|
|
25
|
+
// and the scopes in the manifest `surface_manifest` returns once this entry is declared.
|
|
26
|
+
// See docs/deploy/surfaces/slack.md#search-slack-as-you.
|
|
19
27
|
|
|
20
28
|
import { defineMcpServers } from "@open-everywhere/core/agent/connections/mcp-servers.js";
|
|
21
29
|
|
|
22
30
|
export const MCP_SERVERS = defineMcpServers([
|
|
31
|
+
// Example — "search Slack as you" on your own Slack app. Import it first:
|
|
32
|
+
// import { slackAsYou } from "@open-everywhere/provider-slack/agent/slack-as-you.js";
|
|
33
|
+
//
|
|
34
|
+
// slackAsYou({ clientId: "<your Slack app's Client ID>" }),
|
|
35
|
+
//
|
|
23
36
|
// Example — a vendor with dynamic client registration (the common case). Take the URL from the
|
|
24
37
|
// vendor's own MCP documentation:
|
|
25
38
|
//
|
|
@@ -27,6 +40,9 @@ export const MCP_SERVERS = defineMcpServers([
|
|
|
27
40
|
// name: "fullstory",
|
|
28
41
|
// url: "https://<the vendor's hosted MCP endpoint>",
|
|
29
42
|
// description: "FullStory: search sessions, read session summaries and product analytics.",
|
|
43
|
+
// // Optional. The OAuth scopes the sign-in asks for; absent ⇒ no scope parameter is sent and the
|
|
44
|
+
// // vendor's default applies. Name the read scopes first: a person's token holds only these.
|
|
45
|
+
// signIn: { scopes: ["read:sessions"] },
|
|
30
46
|
// },
|
|
31
47
|
//
|
|
32
48
|
// Example — a vendor WITHOUT dynamic registration. Create the client in the vendor's developer
|
|
@@ -43,6 +59,7 @@ export const MCP_SERVERS = defineMcpServers([
|
|
|
43
59
|
// clientId: "public-client-id",
|
|
44
60
|
// clientSecretRef: "db:acme:oauth-client-secret",
|
|
45
61
|
// bodyEncoding: "form",
|
|
62
|
+
// scopes: ["accounts.read", "deals.read"], // optional: the scopes the authorize URL asks for
|
|
46
63
|
// },
|
|
47
64
|
// },
|
|
48
65
|
]);
|
|
@@ -72,6 +72,10 @@ set up, they just ask. Pick the move that fits the shape of the ask:
|
|
|
72
72
|
offer to set it up with `create_routine` so it just happens without anyone asking.
|
|
73
73
|
- **Make it a skill.** A multi-step way-of-doing-things recurs: capture it with
|
|
74
74
|
`create_skill` so next time it's one named move.
|
|
75
|
+
- **Set up a new connector.** "Set up FullStory" or "connect <vendor>" asks for a NEW connector, and that is
|
|
76
|
+
a pull request, not a grant. A worker researches the vendor's hosted MCP server (`web_search`,
|
|
77
|
+
`web_fetch`) and proposes it with `propose_mcp_server`: one entry in `agent/access/mcp-servers.ts`
|
|
78
|
+
on the deployment's config repo, for an admin to merge. It is not set up until the merge.
|
|
75
79
|
|
|
76
80
|
Some of these verbs live on workers rather than on a conversational seat. If a move above
|
|
77
81
|
names a tool you don't hold, that is not a "can't" — delegate it (`agent`) with a brief
|
|
@@ -40,6 +40,8 @@ import { loadSpendCheckpoints } from "../spend/checkpoints.js";
|
|
|
40
40
|
import { loadModelPolicy } from "../model/policy.js";
|
|
41
41
|
import { loadPrincipals } from "../identity/principals.js";
|
|
42
42
|
import { loadGroups } from "../identity/groups.js";
|
|
43
|
+
import { registerA2aAgents } from "@open-everywhere/core/agent/a2a/agents.js";
|
|
44
|
+
import { A2A_AGENTS } from "../access/a2a-agents.js";
|
|
43
45
|
// Side effect: register the operator's per-surface trust registry (identity/trust.ts) at
|
|
44
46
|
// boot, before any binding resolves. Self-registering (calls registerSurfaces on
|
|
45
47
|
// import); nothing to thread through the AppConfig object.
|
|
@@ -96,6 +98,12 @@ registerSettings(SETTINGS_OVERRIDES);
|
|
|
96
98
|
// prices during boot sees a half-wired deployment.
|
|
97
99
|
registerModelPricing(loadModelPricing());
|
|
98
100
|
|
|
101
|
+
// The A2A AGENTS this app declares (OPE-2425, agent/access/a2a-agents.ts) — the only agents
|
|
102
|
+
// `delegate_to_agent` can reach. Registered on core's own slot rather than carried on AppConfig: the
|
|
103
|
+
// list is validated at import (defineA2aAgents throws on a bad entry), and an unregistered list is
|
|
104
|
+
// empty, so a core-only process delegates to nobody.
|
|
105
|
+
registerA2aAgents(A2A_AGENTS);
|
|
106
|
+
|
|
99
107
|
registerConfig({
|
|
100
108
|
loadBundles,
|
|
101
109
|
loadBindings,
|
|
@@ -70,6 +70,12 @@
|
|
|
70
70
|
// Every member outside Slack must be declared internal in agent/identity/surfaces.ts, or the boot
|
|
71
71
|
// refuses the window (memory/domain.ts assertWindowSourcesVouched).
|
|
72
72
|
//
|
|
73
|
+
// 🔴 THE DEFAULT IS UNIFIED. A declared domain that omits `mode` shares ONE window across its
|
|
74
|
+
// rooms (OPE-2412). It falls back to solo, and the boot logs why, when its reach holds a tenant or
|
|
75
|
+
// glob entry or a room outside Slack is not declared internal. A one-room domain stays solo. To
|
|
76
|
+
// keep each room in its own seat, write `mode: "solo"` on the domain. `org`, `public` and `dm`
|
|
77
|
+
// below are always solo.
|
|
78
|
+
//
|
|
73
79
|
// --- CRITERIA PSEUDO-DOMAINS (optional) — selected by trust/mode, not a channel list.
|
|
74
80
|
// Each is a singleton (at most one per match) with the full domain toolkit.
|
|
75
81
|
//
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// inbound-webhook surface (docs/capabilities/proactivity-and-routines.md in the Open Everywhere repository "Inbound
|
|
3
3
|
// webhook triggers"). Declare a hook: which signature scheme its sender uses (`source`),
|
|
4
4
|
// where its shared secret lives (`secretRef` + the `broker` that ref resolves through),
|
|
5
|
-
//
|
|
6
|
-
// fires. Point the provider at `POST /webhooks/<id>` (channels/webhooks.ts).
|
|
5
|
+
// where it fires (a room on Slack, Discord or Teams, or a person's DM), and what the agent
|
|
6
|
+
// should do when it fires. Point the provider at `POST /webhooks/<id>` (channels/webhooks.ts).
|
|
7
7
|
//
|
|
8
8
|
// SIGNATURE SCHEME: `source` names the registered verifier. `"oe-standard-webhook"` is
|
|
9
9
|
// OUR own contract — the public standard-webhooks spec (`webhook-id` + `webhook-timestamp`
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
// the seam a DB/dashboard would swap behind, same as memory/config/domains.ts and access/
|
|
51
51
|
// bundles.ts. After adding a hook: `npm run typecheck` plus a boot (assertWebhooksValid runs
|
|
52
52
|
// at import time and throws on a malformed entry — id collisions, a missing source, a
|
|
53
|
-
// blank/empty secretRef, a missing broker, a target that
|
|
54
|
-
//
|
|
53
|
+
// blank/empty secretRef, a missing broker, a target that is neither a room
|
|
54
|
+
// "<platform>/<workspace>/<surface>" nor a person "dm:<principal key>").
|
|
55
55
|
|
|
56
56
|
import { defineWebhook, assertWebhooksValid, type WebhookHook } from "@open-everywhere/core/agent/webhooks/config.js";
|
|
57
57
|
import { loadHooksOverlay } from "./hooks-overlay.js";
|
|
@@ -64,7 +64,7 @@ const hooks: WebhookHook[] = [
|
|
|
64
64
|
// source: "oe-standard-webhook", // OUR contract — a sender you control signs it
|
|
65
65
|
// secretRef: "DEPLOY_STATUS_WEBHOOK_SECRET", // shared secret REF (env var NAME here, not the value)
|
|
66
66
|
// broker: "env", // the home that ref resolves through ("env" | "db" | ...)
|
|
67
|
-
// target: "slack/<team-id>/<channel-id>", //
|
|
67
|
+
// target: "slack/<team-id>/<channel-id>", // a room on any surface, or "dm:<principal key>" for a person
|
|
68
68
|
// readableBy: [{ level: "domain", domain: "engineering" }], // WHO may read its events — REQUIRED, no default
|
|
69
69
|
// posture: "projection", // HOW MUCH of the payload reaches the model
|
|
70
70
|
// project: ["status", "branch"], // …under "projection": exactly these normalizer field keys
|
|
@@ -58,10 +58,12 @@
|
|
|
58
58
|
"hook/spend": "mounted",
|
|
59
59
|
"hook/stall-guard": "mounted",
|
|
60
60
|
"hook/telemetry": "mounted",
|
|
61
|
+
"hook/tool-usage": "mounted",
|
|
61
62
|
"hook/turn-anchor": "mounted",
|
|
62
63
|
"hook/wake-accounting-turn": "mounted",
|
|
63
64
|
"hook/wake-turn-start": "mounted",
|
|
64
65
|
"hook/window-routing": "mounted",
|
|
66
|
+
"schedule/audit-export": "mounted",
|
|
65
67
|
"schedule/directory-sync": "mounted",
|
|
66
68
|
"schedule/dispatch": "mounted",
|
|
67
69
|
"schedule/dream-mode3": "mounted",
|
|
@@ -78,6 +80,7 @@
|
|
|
78
80
|
"tool/cancel_routine": "mounted",
|
|
79
81
|
"tool/cancel_work": "mounted",
|
|
80
82
|
"tool/capture_events": "mounted",
|
|
83
|
+
"tool/check_agent_task": "mounted",
|
|
81
84
|
"tool/check_pr_status": "mounted",
|
|
82
85
|
"tool/checkout_repo": "mounted",
|
|
83
86
|
"tool/clear_connector_override": "mounted",
|
|
@@ -91,6 +94,7 @@
|
|
|
91
94
|
"tool/create_skill": "mounted",
|
|
92
95
|
"tool/create_ticket": "mounted",
|
|
93
96
|
"tool/declare_webhook": "mounted",
|
|
97
|
+
"tool/delegate_to_agent": "mounted",
|
|
94
98
|
"tool/delete_skill": "mounted",
|
|
95
99
|
"tool/describe_image": "mounted",
|
|
96
100
|
"tool/dm_person": "mounted",
|
|
@@ -116,6 +120,7 @@
|
|
|
116
120
|
"tool/post_file": "mounted",
|
|
117
121
|
"tool/post_message": "mounted",
|
|
118
122
|
"tool/post_pr_walkthrough": "mounted",
|
|
123
|
+
"tool/propose_mcp_server": "mounted",
|
|
119
124
|
"tool/purge_memory": "mounted",
|
|
120
125
|
"tool/query_analytics": "mounted",
|
|
121
126
|
"tool/react": "mounted",
|
|
@@ -156,6 +161,7 @@
|
|
|
156
161
|
"tool/unlink_identity": "mounted",
|
|
157
162
|
"tool/update_status": "mounted",
|
|
158
163
|
"tool/usage_report": "mounted",
|
|
164
|
+
"tool/waiting_on_me": "mounted",
|
|
159
165
|
"tool/walk_pr": "mounted",
|
|
160
166
|
"tool/work": "mounted"
|
|
161
167
|
}
|
|
@@ -44,11 +44,13 @@ agent/hooks/spawn-taint.ts mounted @open-everywhere/core
|
|
|
44
44
|
agent/hooks/spend.ts mounted @open-everywhere/core
|
|
45
45
|
agent/hooks/stall-guard.ts mounted @open-everywhere/core
|
|
46
46
|
agent/hooks/telemetry.ts mounted @open-everywhere/core
|
|
47
|
+
agent/hooks/tool-usage.ts mounted @open-everywhere/core
|
|
47
48
|
agent/hooks/turn-anchor.ts mounted @open-everywhere/core
|
|
48
49
|
agent/hooks/wake-accounting-turn.ts mounted @open-everywhere/core
|
|
49
50
|
agent/hooks/wake-turn-start.ts mounted @open-everywhere/core
|
|
50
51
|
agent/hooks/window-routing.ts mounted @open-everywhere/core
|
|
51
52
|
agent/lib/providers.generated.ts providers slack,notion,github
|
|
53
|
+
agent/schedules/audit-export.ts mounted @open-everywhere/core
|
|
52
54
|
agent/schedules/directory-sync.ts mounted @open-everywhere/core
|
|
53
55
|
agent/schedules/dispatch.ts mounted @open-everywhere/core
|
|
54
56
|
agent/schedules/dream-mode3.ts mounted @open-everywhere/core
|
|
@@ -67,6 +69,7 @@ agent/tools/browser_tools.ts mounted @open-everywhere/core
|
|
|
67
69
|
agent/tools/cancel_routine.ts mounted @open-everywhere/core
|
|
68
70
|
agent/tools/cancel_work.ts mounted @open-everywhere/core
|
|
69
71
|
agent/tools/capture_events.ts mounted @open-everywhere/core
|
|
72
|
+
agent/tools/check_agent_task.ts mounted @open-everywhere/core
|
|
70
73
|
agent/tools/check_pr_status.ts mounted @open-everywhere/core
|
|
71
74
|
agent/tools/checkout_repo.ts mounted @open-everywhere/core
|
|
72
75
|
agent/tools/clear_connector_override.ts mounted @open-everywhere/core
|
|
@@ -80,6 +83,7 @@ agent/tools/create_routine.ts mounted @open-everywhere/core
|
|
|
80
83
|
agent/tools/create_skill.ts mounted @open-everywhere/core
|
|
81
84
|
agent/tools/create_ticket.ts mounted @open-everywhere/core
|
|
82
85
|
agent/tools/declare_webhook.ts mounted @open-everywhere/core
|
|
86
|
+
agent/tools/delegate_to_agent.ts mounted @open-everywhere/core
|
|
83
87
|
agent/tools/delete_skill.ts mounted @open-everywhere/core
|
|
84
88
|
agent/tools/describe_image.ts mounted @open-everywhere/core
|
|
85
89
|
agent/tools/dm_person.ts mounted @open-everywhere/core
|
|
@@ -107,6 +111,7 @@ agent/tools/permission_fit_report.ts mounted @open-everywhere/core
|
|
|
107
111
|
agent/tools/post_file.ts mounted @open-everywhere/core
|
|
108
112
|
agent/tools/post_message.ts mounted @open-everywhere/core
|
|
109
113
|
agent/tools/post_pr_walkthrough.ts mounted @open-everywhere/core
|
|
114
|
+
agent/tools/propose_mcp_server.ts mounted @open-everywhere/core
|
|
110
115
|
agent/tools/purge_memory.ts mounted @open-everywhere/core
|
|
111
116
|
agent/tools/query_analytics.ts mounted @open-everywhere/core
|
|
112
117
|
agent/tools/react.ts mounted @open-everywhere/core
|
|
@@ -150,6 +155,7 @@ agent/tools/subscribe_pr.ts mounted @open-everywhere/core
|
|
|
150
155
|
agent/tools/unlink_identity.ts mounted @open-everywhere/core
|
|
151
156
|
agent/tools/update_status.ts mounted @open-everywhere/core
|
|
152
157
|
agent/tools/usage_report.ts mounted @open-everywhere/core
|
|
158
|
+
agent/tools/waiting_on_me.ts mounted @open-everywhere/core
|
|
153
159
|
agent/tools/walk_pr.ts mounted @open-everywhere/core
|
|
154
160
|
agent/tools/web_fetch.ts framework-disabled
|
|
155
161
|
agent/tools/work.ts mounted @open-everywhere/core
|