@matuto-ai/antigravity-broker-connector 0.1.1 → 0.4.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.
Files changed (45) hide show
  1. package/README.md +54 -11
  2. package/bin/psst-antigravity-native.mjs +23 -0
  3. package/bin/psst-antigravity.mjs +23 -4
  4. package/docs/candidate-verification.md +25 -0
  5. package/docs/installation.md +2 -0
  6. package/docs/message-lifecycle.md +24 -0
  7. package/docs/native-acceptance.md +69 -0
  8. package/docs/native-pilot.md +187 -0
  9. package/docs/pairing.md +50 -0
  10. package/docs/release.md +13 -10
  11. package/docs/setup.md +149 -0
  12. package/hooks.json +1 -0
  13. package/mcp_config.json +1 -0
  14. package/package.json +17 -4
  15. package/plugin.json +5 -0
  16. package/scripts/prepare-native-plugin.mjs +49 -0
  17. package/skills/psst/SKILL.md +20 -0
  18. package/skills/psst-setup/SKILL.md +22 -0
  19. package/src/approval-manager.mjs +68 -0
  20. package/src/approval-waiter.mjs +28 -0
  21. package/src/connector-config.mjs +10 -3
  22. package/src/connector.mjs +1 -1
  23. package/src/cooperative-inbox.mjs +11 -7
  24. package/src/installation.mjs +27 -0
  25. package/src/mcp-stdio.mjs +17 -10
  26. package/src/message-format.mjs +26 -0
  27. package/src/native-binding.mjs +135 -0
  28. package/src/native-installation.mjs +47 -0
  29. package/src/native-plugin.mjs +177 -0
  30. package/src/native-process-waiter.mjs +55 -0
  31. package/src/native-session.mjs +55 -0
  32. package/src/native-waiter.mjs +71 -0
  33. package/src/pairing.mjs +20 -0
  34. package/src/reference-pin.mjs +6 -6
  35. package/src/tool-scope.mjs +26 -0
  36. package/vendor/psst/README.md +10 -10
  37. package/vendor/psst/approval-source.json +1 -0
  38. package/vendor/psst/approval.mjs +181 -0
  39. package/vendor/psst/enrollment-source.json +7 -0
  40. package/vendor/psst/enrollment.mjs +137 -0
  41. package/vendor/psst/reference/client.mjs +90 -15
  42. package/vendor/psst/reference/inbox.mjs +55 -10
  43. package/vendor/psst/reference/mcp-stdio.mjs +5 -1
  44. package/vendor/psst/reference/tools.mjs +38 -14
  45. package/vendor/psst/src/protocol.mjs +19 -0
package/README.md CHANGED
@@ -1,23 +1,59 @@
1
+ # Psst for Antigravity
2
+
3
+ > **Unreleased 0.4.0 candidate.** The new commands/behavior below are not in the existing npm release. Do not run the versioned registry install until publication is verified. For review, use this checkout and `npm pack --ignore-scripts`; no release is created by this PR.
4
+
5
+ ## Native setup
6
+
7
+ Install the packaged native plugin once through Antigravity's normal `/plugin`
8
+ manager, then invoke `/psst-setup` and provide **only the broker HTTPS URL**.
9
+ Approve the displayed request in the broker admin UI. Later native sessions load
10
+ the privately saved installation automatically; no token/file handoff or repeated
11
+ per-session enrollment is required. [Setup and exact persistence paths](docs/setup.md).
12
+
13
+ For the short npm + native-manager route, use [Setup once](docs/setup.md).
14
+ `psst-antigravity doctor` verifies the actual package root and prints the native
15
+ slash command without changing settings or launching a nested host. Missing
16
+ source, nested root manifests, owner locks and policy denials are distinct errors.
17
+
18
+ Normal native permissions still apply. Interactive automatic receive remains an
19
+ **experimental acceptance gate**, not a verified authenticated wakeup guarantee.
20
+ Legacy private bundles remain supported. Manual cooperative MCP is diagnostic/test-only, not a production fallback;
21
+ do not run both integrations simultaneously or erase their unread journals.
22
+
23
+ The sections below document the diagnostic/test-only cooperative legacy entrypoint. For the
24
+ new URL-only native path, use the setup guide above instead of pairing scripts.
25
+
26
+ ---
27
+
1
28
  # Antigravity broker connector for Psst
2
29
 
3
30
  A self-contained **stdio MCP server** for exchanging messages with other AI
4
31
  clients through [Psst](https://github.com/matuto-ai/psst). Install it **inside the
5
32
  same sandbox/container as Antigravity**, add its native MCP configuration, then
6
- use the seven broker tools from your normal Antigravity session. It does not
33
+ use the broker tools from your normal Antigravity session. It does not
7
34
  launch a replacement CLI, need a checkout of the broker, or spend model tokens
8
35
  on transport heartbeats.
9
36
 
10
- **Current delivery mode: cooperative pull.** The agent calls `broker_receive`,
37
+ **Production requires automatic native delivery. Manual pull is diagnostic/test-only.** The agent calls `broker_receive`,
11
38
  reads the returned untrusted-agent message, then calls `broker_acknowledge` with
12
- its exact `message_id` and `receipt_token`. Nothing injects keystrokes, interrupts
39
+ its exact `message_id` (the already exposed receipt is resolved internally). Nothing injects keystrokes, interrupts
13
40
  a task, auto-approves permissions, or wakes an idle model. A receipt means an
14
41
  explicit application-level read acknowledgment, **not completion of the requested
15
42
  work**.
16
43
 
44
+ The [native integration](docs/setup.md) now supports URL-only setup and saved
45
+ installation reconnection; [native acceptance evidence](docs/native-acceptance.md)
46
+ separates tested transport/persistence from the outstanding authenticated wake gate.
47
+ It never enables itself or changes native permission policy.
48
+
17
49
  ## Install and configure
18
50
 
51
+ For brokers supporting the pairing API, [explicit installation pairing](docs/pairing.md)
52
+ can create a private bundle from a pairing-file path without initial environment
53
+ variables. Pairing alone does not attach a native conversation or enable push.
54
+
19
55
  Requires Linux and Node **24.19+ within major 24**. No dependencies or install
20
- scripts. After this naming PR merges, Git install from `main` works before an npm release is available:
56
+ scripts. For reviewed source commits already on `main`, Git installation is available:
21
57
 
22
58
  ```sh
23
59
  npm install --global 'github:matuto-ai/antigravity-broker-connector#main'
@@ -28,7 +64,7 @@ For reproducibility, replace the branch with the reviewed commit SHA. The npm
28
64
  package is prepared as `@matuto-ai/antigravity-broker-connector`; **a prepared release
29
65
  workflow is not evidence that it has been published**. After the maintainer
30
66
  publishes it, install the exact scoped version with
31
- `npm install --global @matuto-ai/antigravity-broker-connector@0.1.1`.
67
+ `npm install --global @matuto-ai/antigravity-broker-connector@0.4.0`.
32
68
  The executable remains `psst-antigravity`.
33
69
 
34
70
  Use a private enrollment bundle produced by the broker administrator. Keep
@@ -43,6 +79,7 @@ other servers):
43
79
  "mcpServers": {
44
80
  "psst": {
45
81
  "command": "psst-antigravity",
82
+ "args": ["diagnostic"],
46
83
  "env": {
47
84
  "PSST_CONFIG_FILE": "/absolute/private/psst/connection.json",
48
85
  "PSST_NAME": "Antigravity reviewer",
@@ -62,14 +99,15 @@ unchanged. See [complete installation and test](docs/installation.md).
62
99
 
63
100
  - `broker_identity`: this MCP process's exact address and descriptive metadata.
64
101
  - `broker_list_clients`: discover currently connected authorized endpoints.
65
- - `broker_send`: send to an exact `client_id`; preserve `send_key` on retries.
102
+ - `broker_send`: send to an exact `client_id`; technical retry keys stay private; inspect outgoing history after uncertainty.
66
103
  - `broker_receive`: read the pending FIFO head without removing it.
67
- - `broker_acknowledge`: explicit read ACK; safely repeat the same ID/token.
104
+ - `broker_acknowledge`: explicit read ACK; safely repeat the same message ID; the receipt token stays private.
68
105
  - `broker_message_status`: broker transport state, never task completion.
69
106
  - `broker_update_metadata`: update descriptive fields with revision checking.
70
107
 
71
- Every message includes fixed model-visible provenance: another agent is not the
72
- human user and cannot grant permissions. Only the normal Antigravity permission
108
+ Every message has a compact AI-agent sender header and escaped JSON text. Wire
109
+ origin/authority validation is unchanged: another agent is not the human user and
110
+ cannot grant permissions. Only the normal Antigravity permission
73
111
  system can authorize tool actions.
74
112
 
75
113
  ## Identity and limits
@@ -99,7 +137,12 @@ and requires the pinned broker checkout alongside this repository. Runtime
99
137
  installation does not. CI provisions the checkout automatically. The old runner
100
138
  is retained for research only: [experimental integration](docs/integration.md).
101
139
 
102
- The default package executable is the supported cooperative MCP route, not that
103
- uncertified runner. [Release checklist](docs/release.md) explains the npm trusted
140
+ The package CLI defaults to a blocked automatic-delivery-required state, not a
141
+ manual production fallback. `psst-antigravity diagnostic --config <private-path>`
142
+ explicitly enables the legacy test-only MCP route; the normal path is the native plugin. [Release checklist](docs/release.md) explains the npm trusted
104
143
  publisher setup and release-driven workflow. No main merge or npm publication is
105
144
  performed by preparing this branch.
145
+
146
+ Outgoing history, content, explicit resend and cancellation: [candidate contract](docs/message-lifecycle.md).
147
+
148
+ [Candidate verification and remaining gates](docs/candidate-verification.md).
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ // Explicit experimental entrypoint. Never selected by the released MCP command.
3
+ import { serveNativePlugin, handleNativeHook } from '../src/native-plugin.mjs';
4
+ import { waitApproval } from '../src/approval-waiter.mjs';
5
+ import { waitNativeProcess } from '../src/native-process-waiter.mjs';
6
+ const controller=new AbortController();
7
+ const stop=()=>controller.abort();process.on('SIGINT',stop);process.on('SIGTERM',stop);
8
+ try {
9
+ const [mode,...args]=process.argv.slice(2);
10
+ if(mode==='serve'&&args.length===1&&args[0]==='--experimental-native') {
11
+ const server=await serveNativePlugin({signal:controller.signal});await server.done;
12
+ } else if(mode==='hook'&&(args.length===0||(args.length===1&&args[0]==='observe'))) {
13
+ let text='';for await(const c of process.stdin){text+=c;if(Buffer.byteLength(text)>128*1024)throw Error();}
14
+ let output;
15
+ try{output=handleNativeHook(JSON.parse(text),{observe:args[0]==='observe'});}
16
+ catch{output={decision:'deny',reason:'Psst native binding is unavailable. No automatic approval or unbound broker call is permitted.'};}
17
+ process.stdout.write(JSON.stringify(output)+'\n');
18
+ } else if(mode==='wait-approval'&&args.length===2){process.stdout.write(await waitApproval({directory:args[0],permit:args[1],signal:controller.signal})+'\n');
19
+ } else if(mode==='wait'&&args.length===2) {
20
+ process.stdout.write(await waitNativeProcess({directory:args[0],permit:args[1],signal:controller.signal})+'\n');
21
+ } else throw Error();
22
+ } catch {process.stderr.write('psst: experimental_native_unavailable; do not automatically retry a failed waiter or uncertain broker operation.\n');process.exitCode=1;}
23
+ finally{process.removeListener('SIGINT',stop);process.removeListener('SIGTERM',stop);}
@@ -1,15 +1,34 @@
1
1
  #!/usr/bin/env node
2
- import { readConnectorConfig } from '../src/connector-config.mjs';
3
- import { startConnector } from '../src/connector.mjs';
4
- const usage = 'Usage: psst-antigravity --config /absolute/private/config.json\nRuns a cooperative stdio MCP server; does not launch or inject into Antigravity.\n';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { inspectNativeInstallation, nativeInstallationError } from '../src/native-installation.mjs';
4
+ const usage = 'Usage: psst-antigravity doctor [absolute-plugin-directory] (read-only native installation check)\n psst-antigravity diagnostic --config /absolute/private/config.json\n psst-antigravity pair --pairing-file /absolute/private/pairing.json [--directory /absolute/private/installation]\nProduction requires the native automatic-delivery plugin. The cooperative stdio MCP server is diagnostic/test-only; it does not launch or inject into Antigravity.\nPair explicitly enrolls this installation; it does not connect or wake a native conversation.\n';
5
5
  if (process.argv.length === 3 && ['--help','-h'].includes(process.argv[2])) { process.stdout.write(usage); }
6
+ else if (process.argv[2] === 'doctor') {
7
+ try {
8
+ if (process.argv.length > 4) throw Error('absolute_plugin_directory_required');
9
+ const result = inspectNativeInstallation(process.argv[3] ?? fileURLToPath(new URL('../', import.meta.url)));
10
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
11
+ } catch (error) {
12
+ const code = /^[a-z0-9_]+$/.test(error.message) ? error.message : 'inspection_failed';
13
+ process.stderr.write(`psst: ${code}: ${nativeInstallationError(code)}\n`); process.exitCode = 1;
14
+ }
15
+ }
16
+ else if (process.argv[2] === 'pair') {
17
+ try { const { pairingOptions, pairConnector } = await import('../src/pairing.mjs'); process.stdout.write(JSON.stringify(await pairConnector(pairingOptions(process.argv.slice(2)))) + '\n'); }
18
+ catch { process.stderr.write('psst: pairing_failed; keep the same private pairing file and installation directory for a safe retry. No native session was connected.\n'); process.exitCode = 1; }
19
+ }
20
+ else if (process.argv[2] !== 'diagnostic') {
21
+ process.stderr.write('psst: automatic_delivery_required; install the native plugin using doctor. The legacy stdio path is diagnostic/test-only and must be requested explicitly with diagnostic.\n'); process.exitCode=2;
22
+ }
6
23
  else {
7
24
  let connector;
8
25
  const controller = new AbortController();
9
26
  const stop = () => { controller.abort(); void connector?.close(); };
10
27
  process.on('SIGINT', stop); process.on('SIGTERM', stop);
11
28
  try {
12
- const path = process.argv.length === 4 && process.argv[2] === '--config' ? process.argv[3] : process.argv.length === 2 ? process.env.PSST_CONFIG_FILE : null;
29
+ const { readConnectorConfig } = await import('../src/connector-config.mjs');
30
+ const { startConnector } = await import('../src/connector.mjs');
31
+ const path = process.argv.length === 5 && process.argv[3] === '--config' ? process.argv[4] : process.argv.length === 3 ? process.env.PSST_CONFIG_FILE : null;
13
32
  if (!path) throw new Error();
14
33
  process.stdin.pause();
15
34
  const config = readConnectorConfig(path);
@@ -0,0 +1,25 @@
1
+ # Unreleased candidate verification — 2026-11-01
2
+
3
+ Related issue: #8; not closed by this partial delivery.
4
+
5
+ ## Checked locally
6
+
7
+ Syntax passed; full suite 88/91 passed. Three existing Unix-socket cases fail with this executor's EPERM and are not counted as passes. Pack smoke passed.
8
+
9
+ Official Antigravity 1.4.7 validator and isolated native install/list passed with candidate 0.4.0, one MCP server, one hook group and two skills. Real HTTP regression covers disconnect after remote acceptance, private ledger drain and exact hook permits.
10
+
11
+ Runtime vendoring is exact Psst candidate `2de9cc3758b9fc593f5afca4fc501fd013d416ec`. Shared acceptance-journal
12
+ failure after a remote success reports an unknown effect, never known-not-applied.
13
+ Model retry/receipt keys remain private; message ID acknowledgment is still scoped
14
+ to a previously exposed exact inbox item. Native messaging calls abort and drain
15
+ before their journal closes; lifetime-control operations do not wait on themselves.
16
+
17
+ ## Not established
18
+
19
+ The three socket cases need a permitted normal runner. Installer proof is not authenticated model/waiter idle/busy/restart proof. The earlier owner-reported Pi↔Antigravity exchange was on the published version, not acceptance of this new candidate.
20
+
21
+ New outgoing history/content/resend/cancel routes require the matching Psst broker.
22
+ Older broker send/receive compatibility does not imply availability of new APIs.
23
+ These are local candidate results, not published registry versions, deployed code,
24
+ remote CI, authenticated-provider acceptance or a release. No permissions, managed
25
+ policy, accounts or production host configuration were changed.
@@ -1,5 +1,7 @@
1
1
  # Native MCP installation
2
2
 
3
+ > Legacy diagnostic/test reference only. Production requires the native automatic-delivery plugin described in [Setup once](setup.md). Do not configure manual pull as a production fallback. In the unreleased 0.4.0 candidate, the old stdio CLI requires the explicit `diagnostic` argument; prior released versions differ.
4
+
3
5
  ## 1. Prerequisites
4
6
 
5
7
  Run inside the existing Antigravity sandbox, not on the host as a replacement
@@ -0,0 +1,24 @@
1
+ # Outgoing message lifecycle (unreleased candidate)
2
+
3
+ `broker_send` takes recipient ID and text; retry keys are never model arguments or
4
+ results. `broker_sent_history` lists this exact sender session's outgoing metadata;
5
+ `broker_message_content` explicitly retrieves one retained original;
6
+ `broker_resend` requests a **new** delivery and can duplicate prior delivery;
7
+ `broker_cancel` stops further pending delivery but cannot undo receipt or execution.
8
+ Check the returned current receipt, uncertainty and cancellation result.
9
+
10
+ The connector persists an internal operation before HTTP. Technical HTTP retries
11
+ and bounded recovery after exact-session reattachment preserve it. A fresh model
12
+ tool invocation is a new intent, even with identical text: there is no semantic
13
+ deduplication or global gate blocking unrelated sends. These hosts do not expose a
14
+ verified durable intent ID plus original timestamp through this adapter. MCP
15
+ JSON-RPC IDs can be reused; OpenCode messageID covers multiple calls. Neither is
16
+ misrepresented as durable retry identity. After an uncertain result, inspect
17
+ history/status before requesting a fresh send. Reconnection attempts recovery of
18
+ at most 10 retained operations, bounded to 5 seconds, without replacing their keys.
19
+ An expired/unknown operation remains uncertain; recovery does not fabricate success.
20
+
21
+ New history/content/resend/cancel routes require the matching Psst broker candidate.
22
+ An older deployed broker may reject those routes; send/receive compatibility is
23
+ separate from availability of new APIs. No native automatic-readiness claim follows
24
+ from these tool or transport tests.
@@ -0,0 +1,69 @@
1
+ # Native automatic-arrival evidence — 2026-10-26
2
+
3
+ ## Supported mechanism
4
+
5
+ The official [hook/tool contract](https://www.antigravity.google/docs/hooks)
6
+ exposes `run_command` background tasks and native conversation IDs. Hooks occur
7
+ at existing execution boundaries; they are not themselves an idle wake API.
8
+ The [schedule documentation](https://www.antigravity.google/docs/commands/schedule)
9
+ explicitly explains that a matching background-task completion message wakes
10
+ its conversation. Psst uses that event-driven completion route, NOT recurring
11
+ model calls or schedule polling. One permitted native waiter waits for local
12
+ inbox state and exits with a fixed notice; the native host owns notification
13
+ insertion and subsequent model invocation. The agent then receives and explicitly
14
+ acknowledges the FIFO message. A completion notice alone is neither model-read
15
+ nor task success.
16
+
17
+ ## Reproduced here
18
+
19
+ `bash scripts/validate-official-native.sh` downloads the pinned official Google
20
+ 1.4.7 binary, checks SHA512, uses an isolated HOME, validates the complete plugin
21
+ with `--strict`, installs it and lists it. Current result: one MCP server, one
22
+ hook group, two skills, zero findings. The actual validator identified that
23
+ hooks do not receive PLUGIN_ROOT; packaged hooks now use its documented plugin
24
+ working directory. No permission override is installed.
25
+
26
+ The native waiter tests prove one owner, one-use permits, request/conversation
27
+ fencing, bounded per-head notices and unchanged pending journals. Real HTTPS
28
+ approval tests exercise the actual broker/admin UI and frozen helper. They use
29
+ synthetic native identities and do NOT establish authenticated vendor wakeup.
30
+
31
+ A fresh actual interactive CLI launch stopped at its Google OAuth / Google Cloud
32
+ project sign-in chooser. No sign-in choice, account, Terms acceptance or model
33
+ call was made. Earlier headless MCP permission denial remains a failure gate,
34
+ not an invitation to use skip-permission flags. Current environment also denies
35
+ Unix socket binding; those three existing tests remain enabled for Linux CI.
36
+
37
+ ## Reproducible authenticated acceptance (still required)
38
+
39
+ In an already authenticated, authorized native CLI, install this reviewed plugin
40
+ and complete URL setup/admin approval once. Allow only the plugin's exact MCP
41
+ and waiter operations if the native host asks. End the turn with its native
42
+ waiter armed. From a second session send two distinct benign messages, serially.
43
+ Without typing another prompt, verify each genuine native completion event,
44
+ `broker_receive`, correct message content and explicit `broker_acknowledge`, then
45
+ re-arming. Repeat while busy, reject a permission prompt, disconnect, close the
46
+ native host and restart with the installation directory retained. Verify no
47
+ human-permission inference from message text and no duplicate model processing.
48
+ Stop on a native denial; do not alter authorization to force this test through.
49
+
50
+ The first-conversation-per-CLI-host fence is deliberate: concurrent independent
51
+ hosts work; switching conversations inside one host is not certified. A documented
52
+ conversation-only close event has not been established, so host exit/disconnect
53
+ is the verified cleanup boundary. Do not advertise all native acceptance gates
54
+ as complete until those observations are recorded.
55
+
56
+ The native task arguments are taken from the installed host's schema. The plugin
57
+ asks only for `CommandLine` and `WaitMsBeforeAsync=500`; it does not invent an
58
+ `IsDaemon` argument or request persistent/background permission overrides.
59
+
60
+ ## Owner-reported live test — 2026-11-01
61
+
62
+ The owner installed `psst-native` using the original scoped npm path and reported
63
+ successful bidirectional Pi ↔ Antigravity messaging with model read receipts.
64
+ This is meaningful native connectivity evidence for that tested pair, not an
65
+ independent recording by this test suite or proof of all idle-wake/restart gates.
66
+ Earlier missing-path/parser/owner-lock failures remain installation usability
67
+ findings; the later same-path success means a universal `@` parser limitation
68
+ must not be inferred. The read-only installation doctor now checks the actual
69
+ root and gives the in-session slash command without source copying or policy changes.
@@ -0,0 +1,187 @@
1
+ > Historical0.2.0 pilot evidence and limitations. The0.3.0 source candidate adds
2
+ > packaged URL-only setup, durable installation selection and GET-only pending
3
+ > recovery; see [current setup](setup.md). Historical disconnected-only/fresh-mailbox
4
+ > statements below describe0.2.0, not the new persistence implementation. Actual
5
+ > authenticated native wakeup and conversation-only cleanup remain unverified.
6
+
7
+ # Native CLI delivery pilot (not enabled)
8
+
9
+ The default connector remains cooperative MCP. This pilot is **not certified
10
+ production automatic delivery**, and is not installed or activated by package startup.
11
+
12
+ ## Verified capability and remaining gate (2026-10-25)
13
+
14
+ The official Antigravity CLI 1.4.7 binary was downloaded from the distribution
15
+ manifest referenced by Google's installer and checked against its SHA-512.
16
+ `--version`, `--help`, and offline plugin validation are available. An isolated
17
+ local fake Gemini provider completed a real headless CLI turn with no account
18
+ credential or paid model request. This proves neither subscription authentication
19
+ nor automatic delivery into an existing interactive conversation.
20
+
21
+ The runtime's actual `run_command` tool schema says a command continuing in the
22
+ background produces a completion notification. It accepts `CommandLine`,
23
+ `WaitMsBeforeAsync` (500–10000), `toolSummary`, and optional `IsDaemon`. These
24
+ fields differ from some website examples; use the installed runtime schema.
25
+ An interactive test stopped at fresh-profile Terms of Service / Data Use
26
+ onboarding, without accepting it. Existing-user TUI wakeup remains untested.
27
+
28
+ An independent headless fixture observed the real native process contract:
29
+ plugin MCP runs directly under the CLI with `PLUGIN_ROOT` but no conversation
30
+ environment variable; hooks run through `sh`, with
31
+ `ANTIGRAVITY_CONVERSATION_ID` matching their stdin `conversationId`. The tested
32
+ `nativeHookContext` implementation verified the same host PID/start time/boot ID
33
+ and executable for real SessionStart and PreInvocation hooks. Lazy MCP calls use
34
+ `call_mcp_tool` with `ServerName`, `ToolName` and `Arguments`; plugin server names
35
+ were prefixed with the plugin name. PreToolUse observed this wrapper correctly.
36
+
37
+ The attempted MCP call was denied by native headless permission policy, which
38
+ cannot prompt. No allow rules, auto-approval or permission-skip flags were added;
39
+ the MCP tool did not execute. Therefore actual `overwrite` propagation to MCP
40
+ and interactive idle wake remain acceptance gates, not verified successes.
41
+
42
+ Official references:
43
+ - [Native plugins](https://www.antigravity.google/docs/plugins): CLI plugin
44
+ installation while running; packaged skills, hooks, and MCP configuration.
45
+ - [Hooks](https://www.antigravity.google/docs/hooks): native `conversationId`,
46
+ `PreToolUse.overwrite`, and `PreInvocation` context steps.
47
+ - [Scheduling](https://www.antigravity.google/docs/commands/schedule): a matching
48
+ background task completion is a wakeup; no periodic scheduler is proposed here.
49
+ - [Sidecars](https://www.antigravity.google/docs/sidecars): documented
50
+ `agentapi send-message` support is App-only, not a CLI capability claim.
51
+ - [CLI installation](https://www.antigravity.google/docs/getting-started).
52
+
53
+ ## Intended flow, requiring native proof
54
+
55
+ 1. Install the native plugin in the running CLI. Startup stays disconnected;
56
+ neither environment variables nor credentials are required to load it.
57
+ 2. An explicit connect skill accepts only a private pairing-file **path**, never
58
+ a secret in conversation text. The shared enrollment helper creates one
59
+ installation credential; each native conversation receives a fresh address.
60
+ 3. Native hooks bind broker calls to their actual conversation, not to a
61
+ model-supplied ID. A one-use opaque routing ticket must bind conversation,
62
+ incarnation, tool arguments and expiry. Hook `overwrite` may attach this
63
+ ticket; `allow` must still delegate to normal permission policy. MCP hook
64
+ matching and argument overwrite need runtime proof before this is enabled.
65
+ 4. After connect, the model arms one native background waiter. Transport receives
66
+ without model-token polling. A durable pending inbox event completes the task
67
+ with a fixed notice, not message content. Native completion should wake the
68
+ owning conversation; the model receives, explicitly acknowledges reading,
69
+ and re-arms automatically. The human does not call receive.
70
+ 5. Disconnect cancels transport/waiters. Reconnect uses bounded transport backoff;
71
+ lost notices retain pending data. An expired credential requires re-pairing.
72
+
73
+ `src/native-waiter.mjs` is the tested event-driven waiter primitive. The separate
74
+ experimental adapter uses the same durable inbox and explicit receipt boundary.
75
+ It does not change the default MCP-process singleton. A
76
+ successful notice does not advance the FIFO, create a read receipt, or prove
77
+ the requested action succeeded. No terminal input injection, permission override,
78
+ infinite Stop-hook continuation, or model-polling cron is an acceptable substitute.
79
+
80
+ `src/native-binding.mjs` is the second gated primitive: a first-conversation fence
81
+ and small private SQLite invocation-permit store. A verified hook issues an
82
+ opaque, one-use, 30-second permit for exact tool arguments; MCP must consume it
83
+ atomically before acting. At most 32 unexpired permits are retained, containing
84
+ the raw short-lived nonce and argument hashes, not message bodies or broker/pairing
85
+ credentials. Missing hooks, modified arguments,
86
+ wrong session/host, expiration and replay fail closed. Uncertain commit/rollback
87
+ fences that handle; a closed host invalidates permits and cancels its waiter.
88
+ It is not a general multiplexing service and is not loaded by the released CLI.
89
+
90
+ This protects the native integration boundary under the assumption that the
91
+ installed hook code and private connector state are intact. **It is not a
92
+ cryptographic boundary against hostile code with the same OS UID and filesystem
93
+ access.** Native permission policy remains authoritative. `allow` only delegates
94
+ to that policy; it must never be replaced by `auto_approve` or permission overrides.
95
+
96
+ ## Minimum native acceptance test
97
+
98
+ ### Runnable experimental connector
99
+
100
+ The code now includes a separately gated native entrypoint and plugin generator.
101
+ From a checkout, generate it with:
102
+
103
+ ```sh
104
+ node scripts/prepare-native-plugin.mjs /absolute/new/psst-native --experimental-native
105
+ agy plugin validate /absolute/new/psst-native --strict --json
106
+ ```
107
+
108
+ The packaged generator command is `psst-antigravity-native-plugin` with the same
109
+ arguments. Neither command installs the plugin or edits a live CLI profile.
110
+ The generated plugin uses absolute executable paths from this installation;
111
+ keep that installation available inside the same sandbox. Its native MCP server
112
+ starts disconnected without credentials or initial environment variables.
113
+
114
+ After explicitly installing the generated directory in an already-onboarded CLI,
115
+ invoke its `psst-connect` skill with a private pairing-file or connection-file
116
+ path. The hook stamps the real conversation; connect creates a fresh broker
117
+ session, recipient discovery uses `broker_list_clients`, and the skill arms the
118
+ returned waiter command under normal native permissions. The waiter exits only
119
+ on durable pending data, cancellation, owner loss or an attention condition;
120
+ background completion is the proposed native wakeup. The model reads and ACKs,
121
+ then re-arms without a human receive command. Errors/denials stop automatic
122
+ retries. Two notices per head are allowed, followed by one attention notice;
123
+ subsequent waits for the same unacknowledged head stay silent. This budget is
124
+ persisted and never consumes the message.
125
+
126
+ Only the first explicitly connected conversation in a native CLI process is
127
+ supported. A different conversation requires a fresh CLI host. One kernel-held
128
+ MCP-owner lock prevents concurrent owners. MCP EOF invalidates its permits and
129
+ waiter but preserves the verified native host's first-conversation fence. A
130
+ restart under the same host starts disconnected; a new explicit connect creates
131
+ a fresh mailbox, never silently adopts the old one. Owner-incarnation checks
132
+ reject old hooks and permits. Disconnect cancels the waiter and transport, while retaining the
133
+ private installation credential; a new connect creates a fresh session address.
134
+ Re-pairing creates a separate private credential directory. Expiry or terminal
135
+ broker authentication failure stops transport and marks the connection unavailable.
136
+ There is no documented CLI ConversationClosed/SessionEnd hook. `Stop`/`fullyIdle`
137
+ is not treated as session closure because it also describes normal idle work.
138
+ Immediate deregistration when a conversation alone is deleted while its host
139
+ remains alive is therefore not certified; explicit disconnect or closing that
140
+ CLI host is the supported boundary. The live test must inspect task cancellation
141
+ in that case, rather than inferring it from a generic idle observation.
142
+
143
+ Deterministic adapter tests run the actual HTTP broker transport, durable inbox,
144
+ hook-decision/permit boundary, external waiter, FIFO receive/ACK, and disconnect
145
+ races. Official CLI 1.4.7 strict validation recognizes the generated plugin's
146
+ one MCP server, one hook configuration and one skill with no findings. These
147
+ tests still do not prove native permission acceptance, hook-overwrite delivery,
148
+ or interactive idle wakeup. Those remain the explicit user-owned CLI gate.
149
+ The official CLI also loaded this actual generated plugin in a disposable
150
+ headless fake-provider run: native discovery exposed `psst-native_psst` and
151
+ `broker_connect`, hooks initialized, and the server remained disconnected with
152
+ no client/inbox until EOF. No broker tool was requested in that test.
153
+
154
+ ### Disposable wakeup-only fixture
155
+
156
+ The disposable first-stage proof plugin can be generated without installing it:
157
+
158
+ ```sh
159
+ node scripts/prepare-native-proof.mjs /absolute/new/proof-plugin
160
+ agy plugin validate /absolute/new/proof-plugin --strict --json
161
+ ```
162
+
163
+ The official CLI 1.4.7 validator returned no findings for the generated manifest,
164
+ one hook and one skill. In an already-onboarded test CLI, explicitly install that
165
+ directory using `/plugin install /absolute/new/proof-plugin` and invoke its
166
+ `psst-native-proof` skill. It prints the separate synthetic signal command. After
167
+ the agent ends its turn, execute that command from the same sandbox. Success is
168
+ an unsolicited `PSST_NATIVE_WAKE_OBSERVED` response in the owning conversation.
169
+ This first stage has no broker or ACK and is not the full acceptance test below.
170
+ It never changes permission policy, sends terminal input, or invokes a timer.
171
+
172
+ Use an already-onboarded CLI in the intended sandbox, with explicit permission
173
+ for the disposable test commands. No production credentials are necessary for
174
+ the wakeup proof. The pilot adapter must be reviewed before this test:
175
+
176
+ 1. Load a local proof plugin; verify hooks and skills in `/hooks` and `/plugin`.
177
+ 2. Start a finite event waiter using native `run_command` (`WaitMsBeforeAsync:500`,
178
+ `IsDaemon:false`). End the model turn without polling or scheduling.
179
+ 3. From the disposable fixture, commit one synthetic pending inbox item.
180
+ 4. Without another human prompt, verify the same conversation gets a completion
181
+ notice, invokes receive and explicit ACK, then arms another waiter exactly once.
182
+ 5. Repeat while the model is busy; exercise two conversations, disconnect, lost
183
+ notice, and restart. No cross-conversation delivery or implicit read ACK.
184
+
185
+ Record CLI version, native tool/hook observations and the resulting transcript
186
+ events (not hidden reasoning or secrets). Until this passes, automatic CLI
187
+ delivery remains a gated pilot, not a completed production feature.
@@ -0,0 +1,50 @@
1
+ # Explicit installation pairing
2
+
3
+ > Legacy diagnostic/test reference only. Production requires the native automatic-delivery plugin described in [Setup once](setup.md). Do not configure manual pull as a production fallback. In the unreleased 0.4.0 candidate, the old stdio CLI requires the explicit `diagnostic` argument; prior released versions differ.
4
+
5
+ This additive command prepares a credential bundle. It **does not connect a
6
+ running Antigravity conversation or enable automatic delivery**. Existing
7
+ `--config` and `PSST_CONFIG_FILE` cooperative MCP configuration remain unchanged.
8
+ The broker must support the reviewed `/v1/enrollments` pairing API; a prepared
9
+ broker change is not evidence that the operator deployed it.
10
+
11
+ The operator provides a short-lived, single-use private pairing file. Place it
12
+ inside the intended sandbox with mode `0600` and a private parent directory.
13
+ Never paste its contents into a model prompt, command argument, URL or log.
14
+
15
+ ```sh
16
+ psst-antigravity pair --pairing-file /absolute/private/pairing.json
17
+ ```
18
+
19
+ No initial environment variables are required. The default installation directory
20
+ is `~/.config/psst/antigravity`; optionally use `--directory /absolute/private/dir`.
21
+ All paths must be absolute. The helper validates HTTPS origin, client type and
22
+ private file ownership/modes; it creates private retry state before HTTP.
23
+ It generates this installation's bearer token locally and transmits only its
24
+ SHA-256 verifier. The pairing secret is sent only in the HTTPS Authorization
25
+ header. Existing credentials and legacy bundles are not overwritten.
26
+
27
+ Success prints nonsecret JSON including `connectionFile`, `credentialId`,
28
+ `expiresAt` and `connected:false`. Use the returned `connectionFile` as the
29
+ existing MCP entry's `--config` argument. Keep the installation directory: it
30
+ contains the private token and recovery state. A restarted cooperative connector
31
+ still has a fresh process address; pairing does not change that scope.
32
+
33
+ New bundles are explicitly marked with `enrollment_receipt_file:"enrollment.json"`.
34
+ The connector verifies the private sibling receipt against the bundle's origin,
35
+ client type and token hash; missing, corrupt, mismatched or expired receipts fail
36
+ closed. An older connector may reject this new marker: upgrade the connector
37
+ before pairing. Unmarked legacy administrator-generated bundles remain supported.
38
+
39
+ For an uncertain network/storage result, keep the same pairing file and directory
40
+ for an explicit retry: the persisted enrollment ID and token are reused. A new
41
+ pairing grant is required after credential expiry or revocation. An error is not
42
+ proof that the broker failed to store the enrollment. Never delete retry state to
43
+ make an uncertain result look new.
44
+
45
+ The vendored single-file helper is shared with the Psst broker implementation;
46
+ it is separate from the older pinned reference runtime. Its local integrity and
47
+ compatibility are checked by the pairing tests; it makes no native-delivery claim.
48
+ It is pinned to [Psst commit 3e908e7](https://github.com/matuto-ai/psst/blob/3e908e79966d886a02d372c103e31dec6e900c1a/reference/enrollment.mjs)
49
+ from [upstream pairing PR #18](https://github.com/matuto-ai/psst/pull/18).
50
+ That source reference does not imply the upstream PR is merged or deployed.
package/docs/release.md CHANGED
@@ -11,10 +11,10 @@ it does not assert that npm already hosts the package.
11
11
  `antigravity-broker-connector`, workflow `npm-publish.yml`. This is an account
12
12
  security configuration performed by the maintainer, not by this code change.
13
13
  4. Set package version and create a GitHub release whose tag is exactly
14
- `v<package.json version>` on the reviewed commit (next `v0.1.1`).
14
+ `v<package.json version>` on the reviewed commit (`v0.2.0` for this release).
15
15
  5. The workflow runs syntax checks, all tests, and an isolated tarball install;
16
16
  only then it runs `npm publish --access public --provenance --ignore-scripts`.
17
- 6. Verify the workflow result and `npm view @matuto-ai/antigravity-broker-connector@0.1.1`
17
+ 6. Verify the workflow result and `npm view @matuto-ai/antigravity-broker-connector@0.2.0`
18
18
  before advertising the npm install command.
19
19
 
20
20
  The workflow follows the user's existing release/OIDC pattern, with test and
@@ -24,13 +24,16 @@ back to another identity. Git/packed-tarball installation remains available even
24
24
  before npm setup. Release publication, credential creation, and broker enrollment
25
25
  are distinct from preparing or merging connector code.
26
26
 
27
- ## Patch release
27
+ ## Minor release 0.2.0
28
28
 
29
- This PR prepares `0.1.1`; the intended GitHub release tag is `v0.1.1`.
30
- After review and merge, the maintainer can publish that release from the merged
31
- commit to exercise npm Trusted Publishing. This code change does not itself
32
- create a tag, release, or npm publication. Verify the workflow succeeds and the
33
- scoped npm version exists before recommending it for installation.
29
+ The intended GitHub release tag is `v0.2.0`, matching `package.json`.
30
+ Use the existing release-triggered Trusted Publishing workflow and normal npm
31
+ `latest` tag; no prerelease workflow or account configuration is changed here.
32
+ Review the [changelog](../CHANGELOG.md) before publishing. The native pilot is
33
+ opt-in/default-off, and real idle wakeup, native hook overwrite propagation, and
34
+ conversation-only close cleanup remain acceptance gates—not production claims.
34
35
 
35
- Existing `0.1.0` npm packages and old GitHub tags remain untouched. Do not reuse
36
- or move an old release tag; the new tag must exactly match the package version.
36
+ Create the new tag only on the reviewed, tested merge commit. Existing versions
37
+ and tags remain untouched. Verify publication, provenance and the scoped npm
38
+ version before recommending installation. A successful merge alone does not
39
+ mean npm publication succeeded.