@embassys/ambassador 0.0.0 → 0.2.7

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.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -2
  3. package/dist/agent-capabilities.d.ts +35 -0
  4. package/dist/agent-capabilities.js +221 -0
  5. package/dist/agent-capabilities.js.map +1 -0
  6. package/dist/ambassador-options.d.ts +6 -0
  7. package/dist/ambassador-options.js +13 -0
  8. package/dist/ambassador-options.js.map +1 -0
  9. package/dist/central-credential.d.ts +41 -0
  10. package/dist/central-credential.js +355 -0
  11. package/dist/central-credential.js.map +1 -0
  12. package/dist/central-enrollment.d.ts +31 -0
  13. package/dist/central-enrollment.js +278 -0
  14. package/dist/central-enrollment.js.map +1 -0
  15. package/dist/central-json.d.ts +8 -0
  16. package/dist/central-json.js +259 -0
  17. package/dist/central-json.js.map +1 -0
  18. package/dist/central-protected-transport.d.ts +21 -0
  19. package/dist/central-protected-transport.js +217 -0
  20. package/dist/central-protected-transport.js.map +1 -0
  21. package/dist/central-rest.d.ts +50 -0
  22. package/dist/central-rest.js +401 -0
  23. package/dist/central-rest.js.map +1 -0
  24. package/dist/cli.d.ts +26 -0
  25. package/dist/cli.js +129 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/credential-store.d.ts +18 -0
  28. package/dist/credential-store.js +617 -0
  29. package/dist/credential-store.js.map +1 -0
  30. package/dist/delivery-profile.d.ts +43 -0
  31. package/dist/delivery-profile.js +253 -0
  32. package/dist/delivery-profile.js.map +1 -0
  33. package/dist/direct-delivery.d.ts +37 -0
  34. package/dist/direct-delivery.js +312 -0
  35. package/dist/direct-delivery.js.map +1 -0
  36. package/dist/dpop.d.ts +28 -0
  37. package/dist/dpop.js +119 -0
  38. package/dist/dpop.js.map +1 -0
  39. package/dist/errors.d.ts +5 -0
  40. package/dist/errors.js +11 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/gateway-application.d.ts +32 -0
  43. package/dist/gateway-application.js +255 -0
  44. package/dist/gateway-application.js.map +1 -0
  45. package/dist/gateway-paths.d.ts +11 -0
  46. package/dist/gateway-paths.js +29 -0
  47. package/dist/gateway-paths.js.map +1 -0
  48. package/dist/guided-registration.d.ts +23 -0
  49. package/dist/guided-registration.js +117 -0
  50. package/dist/guided-registration.js.map +1 -0
  51. package/dist/identity.d.ts +20 -0
  52. package/dist/identity.js +54 -0
  53. package/dist/identity.js.map +1 -0
  54. package/dist/local-mcp.d.ts +28 -0
  55. package/dist/local-mcp.js +410 -0
  56. package/dist/local-mcp.js.map +1 -0
  57. package/dist/local-tool-result.d.ts +4 -0
  58. package/dist/local-tool-result.js +17 -0
  59. package/dist/local-tool-result.js.map +1 -0
  60. package/dist/mcp-contract.d.ts +10 -0
  61. package/dist/mcp-contract.js +63 -0
  62. package/dist/mcp-contract.js.map +1 -0
  63. package/dist/notification-journal.d.ts +24 -0
  64. package/dist/notification-journal.js +194 -0
  65. package/dist/notification-journal.js.map +1 -0
  66. package/dist/notification-relay.d.ts +31 -0
  67. package/dist/notification-relay.js +203 -0
  68. package/dist/notification-relay.js.map +1 -0
  69. package/dist/process-lock.d.ts +8 -0
  70. package/dist/process-lock.js +122 -0
  71. package/dist/process-lock.js.map +1 -0
  72. package/dist/sqlite-artifact.d.ts +7 -0
  73. package/dist/sqlite-artifact.js +121 -0
  74. package/dist/sqlite-artifact.js.map +1 -0
  75. package/dist/webhook-delivery.d.ts +23 -0
  76. package/dist/webhook-delivery.js +122 -0
  77. package/dist/webhook-delivery.js.map +1 -0
  78. package/docs/getting-started-claude.md +33 -0
  79. package/docs/getting-started-codex.md +36 -0
  80. package/docs/getting-started-gemini.md +31 -0
  81. package/docs/getting-started-hermes.md +47 -0
  82. package/docs/getting-started-openclaw.md +48 -0
  83. package/docs/live-qualification.md +174 -0
  84. package/package.json +48 -7
  85. package/index.js +0 -1
@@ -0,0 +1,122 @@
1
+ import { lstatSync } from "node:fs";
2
+ import { mkdir } from "node:fs/promises";
3
+ import { basename, dirname, resolve } from "node:path";
4
+ import Database from "better-sqlite3";
5
+ import { GatewayError } from "./errors.js";
6
+ import { preparePrivateSqliteArtifact } from "./sqlite-artifact.js";
7
+ const LOCK_HANDOFF_TIMEOUT_MS = 1_000;
8
+ const activeLockKeys = new Set();
9
+ const pendingLockPaths = new Set();
10
+ function errorCode(error) {
11
+ if (error !== null && typeof error === "object" && "code" in error) {
12
+ return typeof error.code === "string" ? error.code : undefined;
13
+ }
14
+ return undefined;
15
+ }
16
+ function invalidLockArtifact() {
17
+ return new GatewayError("lock_invalid", "The Ambassador lock artifact is invalid", 7);
18
+ }
19
+ function daemonRunning() {
20
+ return new GatewayError("daemon_running", "Ambassador is already running", 7);
21
+ }
22
+ function pathKey(path) {
23
+ return process.platform === "win32" ? path.toLowerCase() : path;
24
+ }
25
+ function filesystemLockKey(path) {
26
+ try {
27
+ const stats = lstatSync(path, { bigint: true });
28
+ return `artifact:${stats.dev}:${stats.ino}`;
29
+ }
30
+ catch (error) {
31
+ if (errorCode(error) !== "ENOENT")
32
+ throw error;
33
+ const parentStats = lstatSync(dirname(path), { bigint: true });
34
+ return `new:${parentStats.dev}:${parentStats.ino}:${pathKey(basename(path))}`;
35
+ }
36
+ }
37
+ export class ProcessLock {
38
+ database;
39
+ keys;
40
+ released = false;
41
+ constructor(database, keys) {
42
+ this.database = database;
43
+ this.keys = keys;
44
+ }
45
+ static async acquire(path) {
46
+ const artifactPath = resolve(path);
47
+ const pendingPath = pathKey(artifactPath);
48
+ if (pendingLockPaths.has(pendingPath))
49
+ throw daemonRunning();
50
+ pendingLockPaths.add(pendingPath);
51
+ const keys = [];
52
+ try {
53
+ await mkdir(dirname(artifactPath), { recursive: true, mode: 0o700 });
54
+ const initialKey = filesystemLockKey(artifactPath);
55
+ if (activeLockKeys.has(initialKey))
56
+ throw daemonRunning();
57
+ activeLockKeys.add(initialKey);
58
+ keys.push(initialKey);
59
+ pendingLockPaths.delete(pendingPath);
60
+ const artifact = preparePrivateSqliteArtifact(artifactPath, invalidLockArtifact);
61
+ let database;
62
+ try {
63
+ const artifactKey = filesystemLockKey(artifactPath);
64
+ if (artifactKey !== initialKey) {
65
+ if (activeLockKeys.has(artifactKey))
66
+ throw daemonRunning();
67
+ activeLockKeys.add(artifactKey);
68
+ keys.push(artifactKey);
69
+ }
70
+ database = new Database(artifactPath, { timeout: LOCK_HANDOFF_TIMEOUT_MS });
71
+ artifact.validate();
72
+ // Closing another descriptor for this inode after BEGIN can release POSIX process locks.
73
+ artifact.releaseFile();
74
+ database.pragma(`busy_timeout = ${LOCK_HANDOFF_TIMEOUT_MS}`);
75
+ database.pragma("trusted_schema = OFF");
76
+ database.exec("BEGIN EXCLUSIVE");
77
+ artifact.validateDirectory();
78
+ return new ProcessLock(database, keys);
79
+ }
80
+ catch (error) {
81
+ database?.close();
82
+ const code = errorCode(error);
83
+ if (code?.startsWith("SQLITE_BUSY"))
84
+ throw daemonRunning();
85
+ if (code === "SQLITE_NOTADB" || code === "SQLITE_FORMAT" || code === "SQLITE_CORRUPT") {
86
+ throw invalidLockArtifact();
87
+ }
88
+ throw error;
89
+ }
90
+ finally {
91
+ artifact.close();
92
+ }
93
+ }
94
+ catch (error) {
95
+ pendingLockPaths.delete(pendingPath);
96
+ for (const key of keys)
97
+ activeLockKeys.delete(key);
98
+ if (errorCode(error) === "ENOENT" && keys.some((key) => key.startsWith("artifact:"))) {
99
+ throw daemonRunning();
100
+ }
101
+ throw error;
102
+ }
103
+ }
104
+ async release() {
105
+ if (this.released)
106
+ return;
107
+ this.released = true;
108
+ try {
109
+ this.database.exec("ROLLBACK");
110
+ }
111
+ finally {
112
+ try {
113
+ this.database.close();
114
+ }
115
+ finally {
116
+ for (const key of this.keys)
117
+ activeLockKeys.delete(key);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ //# sourceMappingURL=process-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-lock.js","sourceRoot":"","sources":["../src/process-lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface PreparedSqliteArtifact {
2
+ validate: () => void;
3
+ validateDirectory: () => void;
4
+ releaseFile: () => void;
5
+ close: () => void;
6
+ }
7
+ export declare function preparePrivateSqliteArtifact(path: string, invalidArtifact: () => Error): PreparedSqliteArtifact;
@@ -0,0 +1,121 @@
1
+ import { chmodSync, closeSync, constants, fchmodSync, fstatSync, lstatSync, openSync, } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ const POSIX = process.platform !== "win32";
4
+ function errorCode(error) {
5
+ return error !== null && typeof error === "object" && "code" in error
6
+ ? String(error.code)
7
+ : undefined;
8
+ }
9
+ function sameArtifact(left, right) {
10
+ return left.dev === right.dev && left.ino === right.ino;
11
+ }
12
+ function secureExistingFile(path, invalidArtifact) {
13
+ let pathStats;
14
+ try {
15
+ pathStats = lstatSync(path, { bigint: true });
16
+ }
17
+ catch (error) {
18
+ if (errorCode(error) === "ENOENT")
19
+ return;
20
+ throw error;
21
+ }
22
+ if (!pathStats.isFile() || pathStats.nlink !== 1n)
23
+ throw invalidArtifact();
24
+ if (POSIX)
25
+ chmodSync(path, 0o600);
26
+ const currentStats = lstatSync(path, { bigint: true });
27
+ if (!currentStats.isFile() ||
28
+ currentStats.nlink !== 1n ||
29
+ !sameArtifact(pathStats, currentStats)) {
30
+ throw invalidArtifact();
31
+ }
32
+ }
33
+ export function preparePrivateSqliteArtifact(path, invalidArtifact) {
34
+ const directoryPath = dirname(path);
35
+ const initialDirectoryStats = lstatSync(directoryPath, { bigint: true });
36
+ if (!initialDirectoryStats.isDirectory())
37
+ throw invalidArtifact();
38
+ let directoryDescriptor;
39
+ let fileDescriptor;
40
+ try {
41
+ if (POSIX) {
42
+ directoryDescriptor = openSync(directoryPath, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
43
+ const descriptorStats = fstatSync(directoryDescriptor, { bigint: true });
44
+ const pathStats = lstatSync(directoryPath, { bigint: true });
45
+ if (!descriptorStats.isDirectory() || !pathStats.isDirectory())
46
+ throw invalidArtifact();
47
+ if (!sameArtifact(descriptorStats, pathStats))
48
+ throw invalidArtifact();
49
+ if (typeof process.getuid === "function" &&
50
+ descriptorStats.uid !== BigInt(process.getuid())) {
51
+ throw invalidArtifact();
52
+ }
53
+ fchmodSync(directoryDescriptor, 0o700);
54
+ }
55
+ for (const suffix of ["-wal", "-shm", "-journal"]) {
56
+ secureExistingFile(`${path}${suffix}`, invalidArtifact);
57
+ }
58
+ try {
59
+ fileDescriptor = openSync(path, constants.O_CREAT | constants.O_EXCL | constants.O_RDWR, 0o600);
60
+ }
61
+ catch (error) {
62
+ if (errorCode(error) !== "EEXIST")
63
+ throw error;
64
+ const pathStats = lstatSync(path, { bigint: true });
65
+ if (!pathStats.isFile() || pathStats.nlink !== 1n)
66
+ throw invalidArtifact();
67
+ fileDescriptor = openSync(path, constants.O_RDWR | constants.O_NOFOLLOW);
68
+ }
69
+ const validateDirectory = () => {
70
+ const currentDirectoryStats = lstatSync(directoryPath, { bigint: true });
71
+ const expectedDirectoryStats = directoryDescriptor === undefined
72
+ ? initialDirectoryStats
73
+ : fstatSync(directoryDescriptor, { bigint: true });
74
+ if (!currentDirectoryStats.isDirectory() ||
75
+ !sameArtifact(expectedDirectoryStats, currentDirectoryStats)) {
76
+ throw invalidArtifact();
77
+ }
78
+ };
79
+ const validate = () => {
80
+ const descriptorStats = fstatSync(fileDescriptor, { bigint: true });
81
+ const pathStats = lstatSync(path, { bigint: true });
82
+ if (!descriptorStats.isFile() ||
83
+ !pathStats.isFile() ||
84
+ descriptorStats.nlink !== 1n ||
85
+ pathStats.nlink !== 1n ||
86
+ !sameArtifact(descriptorStats, pathStats)) {
87
+ throw invalidArtifact();
88
+ }
89
+ validateDirectory();
90
+ };
91
+ const releaseFile = () => {
92
+ if (fileDescriptor !== undefined) {
93
+ closeSync(fileDescriptor);
94
+ fileDescriptor = undefined;
95
+ }
96
+ };
97
+ validate();
98
+ if (POSIX)
99
+ fchmodSync(fileDescriptor, 0o600);
100
+ return {
101
+ validate,
102
+ validateDirectory,
103
+ releaseFile,
104
+ close: () => {
105
+ releaseFile();
106
+ if (directoryDescriptor !== undefined) {
107
+ closeSync(directoryDescriptor);
108
+ directoryDescriptor = undefined;
109
+ }
110
+ },
111
+ };
112
+ }
113
+ catch (error) {
114
+ if (fileDescriptor !== undefined)
115
+ closeSync(fileDescriptor);
116
+ if (directoryDescriptor !== undefined)
117
+ closeSync(directoryDescriptor);
118
+ throw error;
119
+ }
120
+ }
121
+ //# sourceMappingURL=sqlite-artifact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-artifact.js","sourceRoot":"","sources":["../src/sqlite-artifact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { CentralMessage } from "./central-rest.js";
2
+ export type WebhookDeliveryErrorCode = "delivery_failed" | "invalid_configuration";
3
+ export declare class WebhookDeliveryError extends Error {
4
+ readonly code: WebhookDeliveryErrorCode;
5
+ constructor(code: WebhookDeliveryErrorCode);
6
+ }
7
+ export interface WebhookDeliveryTargetOptions {
8
+ readonly url: string;
9
+ readonly secret: string;
10
+ readonly fetch?: typeof fetch;
11
+ readonly now?: () => number;
12
+ readonly deadlineMs?: number;
13
+ readonly maximumAttempts?: number;
14
+ readonly retryDelayMs?: number;
15
+ }
16
+ export declare class WebhookDeliveryTarget {
17
+ #private;
18
+ constructor(options: WebhookDeliveryTargetOptions);
19
+ deliver(message: CentralMessage, signal: AbortSignal): Promise<{
20
+ readonly status: "accepted";
21
+ }>;
22
+ close(): Promise<void>;
23
+ }
@@ -0,0 +1,122 @@
1
+ import { createHmac, randomUUID } from "node:crypto";
2
+ import { setTimeout as delay } from "node:timers/promises";
3
+ import { canonicalWebhookUrl } from "./delivery-profile.js";
4
+ const DEFAULT_DEADLINE_MS = 10_000;
5
+ const DEFAULT_MAXIMUM_ATTEMPTS = 3;
6
+ const DEFAULT_RETRY_DELAY_MS = 250;
7
+ const MAX_MESSAGE_BYTES = 512 * 1024;
8
+ export class WebhookDeliveryError extends Error {
9
+ code;
10
+ constructor(code) {
11
+ super("Webhook delivery failed");
12
+ this.code = code;
13
+ this.name = "WebhookDeliveryError";
14
+ }
15
+ }
16
+ function positiveInteger(value) {
17
+ return Number.isSafeInteger(value) && value > 0;
18
+ }
19
+ async function cancel(response) {
20
+ await response.body?.cancel().catch(() => undefined);
21
+ }
22
+ export class WebhookDeliveryTarget {
23
+ #url;
24
+ #secret;
25
+ #authorization;
26
+ #fetch;
27
+ #now;
28
+ #deadlineMs;
29
+ #maximumAttempts;
30
+ #retryDelayMs;
31
+ #lifetime = new AbortController();
32
+ constructor(options) {
33
+ try {
34
+ this.#url = canonicalWebhookUrl(options.url);
35
+ }
36
+ catch {
37
+ throw new WebhookDeliveryError("invalid_configuration");
38
+ }
39
+ if (!/^[\x21-\x7e]{32,256}$/u.test(options.secret)) {
40
+ throw new WebhookDeliveryError("invalid_configuration");
41
+ }
42
+ this.#secret = options.secret;
43
+ this.#authorization = `Bearer ${options.secret}`;
44
+ this.#fetch = options.fetch ?? globalThis.fetch;
45
+ this.#now = options.now ?? Date.now;
46
+ this.#deadlineMs = options.deadlineMs ?? DEFAULT_DEADLINE_MS;
47
+ this.#maximumAttempts = options.maximumAttempts ?? DEFAULT_MAXIMUM_ATTEMPTS;
48
+ this.#retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
49
+ if (!positiveInteger(this.#deadlineMs) ||
50
+ !positiveInteger(this.#maximumAttempts) ||
51
+ !positiveInteger(this.#retryDelayMs)) {
52
+ throw new WebhookDeliveryError("invalid_configuration");
53
+ }
54
+ }
55
+ async deliver(message, signal) {
56
+ let body;
57
+ try {
58
+ body = JSON.stringify(message);
59
+ }
60
+ catch {
61
+ throw new WebhookDeliveryError("delivery_failed");
62
+ }
63
+ if (Buffer.byteLength(body, "utf8") > MAX_MESSAGE_BYTES) {
64
+ throw new WebhookDeliveryError("delivery_failed");
65
+ }
66
+ const requestId = message.id ?? randomUUID();
67
+ const deadline = AbortSignal.timeout(this.#deadlineMs);
68
+ const requestSignal = AbortSignal.any([signal, deadline, this.#lifetime.signal]);
69
+ for (let attempt = 1; attempt <= this.#maximumAttempts; attempt += 1) {
70
+ if (requestSignal.aborted)
71
+ throw new WebhookDeliveryError("delivery_failed");
72
+ const now = this.#now();
73
+ if (!Number.isSafeInteger(now) || now < 0) {
74
+ throw new WebhookDeliveryError("invalid_configuration");
75
+ }
76
+ const timestamp = String(Math.floor(now / 1_000));
77
+ const signature = createHmac("sha256", this.#secret)
78
+ .update(timestamp, "ascii")
79
+ .update(".", "ascii")
80
+ .update(body, "utf8")
81
+ .digest("hex");
82
+ try {
83
+ const response = await this.#fetch(this.#url, {
84
+ method: "POST",
85
+ headers: {
86
+ authorization: this.#authorization,
87
+ "content-type": "application/json",
88
+ "idempotency-key": requestId,
89
+ "x-request-id": requestId,
90
+ "x-webhook-timestamp": timestamp,
91
+ "x-webhook-signature-v2": signature,
92
+ },
93
+ body,
94
+ credentials: "omit",
95
+ redirect: "manual",
96
+ signal: requestSignal,
97
+ });
98
+ const accepted = response.status >= 200 && response.status < 300;
99
+ await cancel(response);
100
+ if (accepted)
101
+ return { status: "accepted" };
102
+ }
103
+ catch {
104
+ if (requestSignal.aborted)
105
+ throw new WebhookDeliveryError("delivery_failed");
106
+ }
107
+ if (attempt < this.#maximumAttempts) {
108
+ try {
109
+ await delay(this.#retryDelayMs, undefined, { signal: requestSignal });
110
+ }
111
+ catch {
112
+ throw new WebhookDeliveryError("delivery_failed");
113
+ }
114
+ }
115
+ }
116
+ throw new WebhookDeliveryError("delivery_failed");
117
+ }
118
+ async close() {
119
+ this.#lifetime.abort();
120
+ }
121
+ }
122
+ //# sourceMappingURL=webhook-delivery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-delivery.js","sourceRoot":"","sources":["../src/webhook-delivery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ # Get started with Claude Code
2
+
3
+ ## Before you start
4
+
5
+ - Install Node.js `>=24.19.0 <25`.
6
+ - Use Claude Code `2.1.257` or `2.1.258`.
7
+ - For direct delivery, install `@agentclientprotocol/claude-agent-acp` `0.73.0`
8
+ so `claude-agent-acp` is on `PATH`.
9
+ - Sign in to Claude Code normally. Ambassador never receives your Claude
10
+ credential.
11
+
12
+ ## Set up direct delivery
13
+
14
+ 1. From the directory Claude Code may access, keep Ambassador running:
15
+
16
+ ```sh
17
+ npx --yes @embassys/ambassador@0.2.7 start
18
+ ```
19
+
20
+ 2. Add `http://127.0.0.1:8787/mcp` as a Streamable HTTP MCP server in Claude
21
+ Code's normal MCP configuration. Do not configure authentication.
22
+ 3. Start or restart Claude Code so it sees the MCP server.
23
+ 4. Ask Claude Code to register your email; it calls Ambassador's
24
+ `register_agent` tool.
25
+ 5. Enter the six-digit code sent to your email. Claude Code is direct-only, so
26
+ Ambassador does not ask a delivery question.
27
+
28
+ Ambassador will launch `claude-agent-acp` when a central message arrives. That
29
+ is a new gateway-managed session, not the chat used for registration.
30
+
31
+ Only the exact versions above are enabled. Other versions fail closed until
32
+ their capability profile is reviewed. See [Qualification](qualification.md)
33
+ for compatibility evidence.
@@ -0,0 +1,36 @@
1
+ # Get started with Codex
2
+
3
+ ## Before you start
4
+
5
+ - Install Node.js `>=24.19.0 <25`.
6
+ - Use Codex `0.149.0` or `0.152.1`.
7
+ - For direct delivery, install `@agentclientprotocol/codex-acp` `1.8.0` so
8
+ `codex-acp` is on `PATH`.
9
+ - Sign in to Codex normally. Ambassador never receives your Codex credential.
10
+
11
+ ## Set up direct delivery
12
+
13
+ 1. From the directory Codex may access, keep Ambassador running:
14
+
15
+ ```sh
16
+ npx --yes @embassys/ambassador@0.2.7 start
17
+ ```
18
+
19
+ 2. In another terminal, add its token-free local MCP endpoint:
20
+
21
+ ```sh
22
+ codex mcp add ambassador --url http://127.0.0.1:8787/mcp
23
+ ```
24
+
25
+ 3. Start or restart Codex so it sees the MCP server.
26
+ 4. Ask Codex to register your email; it calls Ambassador's `register_agent`
27
+ tool.
28
+ 5. Enter the six-digit code sent to your email. Codex is direct-only, so
29
+ Ambassador does not ask a delivery question.
30
+
31
+ Ambassador will launch `codex-acp` when a central message arrives. That is a
32
+ new gateway-managed session, not the chat used for registration.
33
+
34
+ Only the exact versions above are enabled. Other versions fail closed until
35
+ their capability profile is reviewed. See [Qualification](qualification.md)
36
+ for compatibility evidence.
@@ -0,0 +1,31 @@
1
+ # Get started with Gemini CLI
2
+
3
+ ## Before you start
4
+
5
+ - Install Node.js `>=24.19.0 <25`.
6
+ - Install and sign in to Gemini CLI `0.58.0`.
7
+ - Gemini supplies native ACP through `gemini --acp`; no adapter is needed.
8
+ - Ambassador never receives your Gemini or Google credential.
9
+
10
+ ## Set up direct delivery
11
+
12
+ 1. From the directory Gemini CLI may access, keep Ambassador running:
13
+
14
+ ```sh
15
+ npx --yes @embassys/ambassador@0.2.7 start
16
+ ```
17
+
18
+ 2. Add `http://127.0.0.1:8787/mcp` as a Streamable HTTP MCP server in Gemini
19
+ CLI's normal MCP configuration. Do not configure authentication.
20
+ 3. Start or restart Gemini CLI so it sees the MCP server.
21
+ 4. Ask Gemini CLI to register your email; it calls Ambassador's
22
+ `register_agent` tool.
23
+ 5. Enter the six-digit code sent to your email. Gemini CLI is direct-only, so
24
+ Ambassador does not ask a delivery question.
25
+
26
+ Ambassador will launch `gemini --acp` when a central message arrives. That is
27
+ a new gateway-managed session, not the chat used for registration.
28
+
29
+ Only the exact version above is enabled. Other versions fail closed until
30
+ their capability profile is reviewed. See [Qualification](qualification.md)
31
+ for compatibility evidence.
@@ -0,0 +1,47 @@
1
+ # Get started with Hermes Agent
2
+
3
+ ## Before you start
4
+
5
+ - Install Node.js `>=24.19.0 <25`.
6
+ - Install and authenticate Hermes Agent `0.21.0`.
7
+ - Make sure `hermes-acp` is on `PATH` for direct delivery.
8
+ - Ambassador never receives your provider credential.
9
+
10
+ ## Set up direct delivery
11
+
12
+ 1. From the directory Hermes may access, keep Ambassador running:
13
+
14
+ ```sh
15
+ npx --yes @embassys/ambassador@0.2.7 start
16
+ ```
17
+
18
+ 2. Add `http://127.0.0.1:8787/mcp` as a Streamable HTTP MCP server in Hermes's
19
+ normal MCP configuration. Do not configure authentication.
20
+ 3. Start or restart Hermes so it sees the MCP server.
21
+ 4. Ask Hermes to register your email; it calls Ambassador's `register_agent`
22
+ tool.
23
+ 5. Choose **Send directly to this Hermes agent**.
24
+ 6. Enter the six-digit code sent to your email.
25
+
26
+ Ambassador will launch `hermes-acp` when a central message arrives. That is a
27
+ new gateway-managed session, not the chat used for registration.
28
+
29
+ ## Use a webhook instead
30
+
31
+ - Before step 1, set the receiver secret in the same shell:
32
+
33
+ ```sh
34
+ export AMBASSADOR_WEBHOOK_SECRET="$(
35
+ node -e "process.stdout.write(require('node:crypto').randomBytes(24).toString('hex'))"
36
+ )"
37
+ ```
38
+
39
+ - During registration, choose **Send to a webhook**.
40
+ - Give Hermes the HTTPS webhook URL and the variable name
41
+ `AMBASSADOR_WEBHOOK_SECRET`.
42
+ - Hermes supplies `delivery.url` and `delivery.secret_env`; it never receives
43
+ the secret value.
44
+
45
+ Only the exact version above is enabled. Other versions fail closed until
46
+ their capability profile is reviewed. See [Qualification](qualification.md)
47
+ for compatibility evidence.
@@ -0,0 +1,48 @@
1
+ # Get started with OpenClaw
2
+
3
+ ## Before you start
4
+
5
+ - Install Node.js `>=24.19.0 <25`.
6
+ - Install and authenticate OpenClaw `2026.8.1`.
7
+ - Make sure `openclaw` is on `PATH` for direct delivery.
8
+ - Ambassador never receives your provider credential.
9
+
10
+ ## Set up direct delivery
11
+
12
+ 1. From the directory OpenClaw may access, keep Ambassador running:
13
+
14
+ ```sh
15
+ npx --yes @embassys/ambassador@0.2.7 start
16
+ ```
17
+
18
+ 2. Add `http://127.0.0.1:8787/mcp` as a Streamable HTTP MCP server in
19
+ OpenClaw's normal MCP configuration. Do not configure authentication.
20
+ 3. Start or restart OpenClaw so it sees the MCP server.
21
+ 4. Ask OpenClaw to register your email; it calls Ambassador's `register_agent`
22
+ tool.
23
+ 5. Choose **Send directly to this OpenClaw agent**.
24
+ 6. Enter the six-digit code sent to your email.
25
+
26
+ Ambassador will launch `openclaw acp` when a central message arrives. OpenClaw
27
+ does not accept session MCP injection, so keep the provider-side MCP entry from
28
+ step 2 configured.
29
+
30
+ ## Use a webhook instead
31
+
32
+ - Before step 1, set the receiver secret in the same shell:
33
+
34
+ ```sh
35
+ export AMBASSADOR_WEBHOOK_SECRET="$(
36
+ node -e "process.stdout.write(require('node:crypto').randomBytes(24).toString('hex'))"
37
+ )"
38
+ ```
39
+
40
+ - During registration, choose **Send to a webhook**.
41
+ - Give OpenClaw the HTTPS webhook URL and the variable name
42
+ `AMBASSADOR_WEBHOOK_SECRET`.
43
+ - OpenClaw supplies `delivery.url` and `delivery.secret_env`; it never receives
44
+ the secret value.
45
+
46
+ Only the exact version above is enabled. Other versions fail closed until
47
+ their capability profile is reviewed. See [Qualification](qualification.md)
48
+ for compatibility evidence.