feat(integrations): notion in-box shim + image provisioning + enable flag (T2)#74
Merged
Merged
Conversation
…flag (T2)
Lets agents in a sandbox type `notion …` / `ntn …` and have the call
routed through the host relay to the host's authenticated `ntn` CLI;
gated by a new typed config flag so the integration is opt-in.
Surface
- packages/sandbox-docker/scripts/ntn-shim — bash shim modeled on
gh-shim. Strict allowlist: `whoami`, `api <endpoint>`, `pages create`,
`pages update`. Anything else dies with a clear message. Installed at
/usr/local/bin/ntn; /usr/local/bin/notion is a symlink to the same
shim (per docs/integrations_backlog.md's per-service surface naming).
Image provisioning (all providers except daytona, which stays
shim-less to match its T1 gh/git decision)
- Dockerfile.box: COPY ntn-shim, chmod, symlink notion.
- apps/cli/scripts/stage-runtime.mjs: stage ntn-shim into the docker
contextFiles + execBitFiles plus the hetzner / vercel / e2b file lists.
- Hetzner install-box.sh, Vercel provision.sh, E2B build-template.sh:
install + symlink the shim.
- Each provider's runtime-assets.ts: map the shim name + remote /tmp
path so the staged file gets uploaded into the prepare VM.
Config flag (opt-in by default)
- packages/config/src/types.ts: new `integrations.notion.enabled` key
(UserConfig, EffectiveConfig, BUILT_IN_DEFAULTS, KEY_REGISTRY entry).
- parse.ts / load.ts / write.ts: parser, merger, and writer now walk
N-level dotted leaves so the 3-level path is natural YAML
(`integrations: { notion: { enabled: true } }`).
Relay gate (cross-provider)
- packages/relay/src/integrations.ts: `refuseIfIntegrationDisabled`
re-reads the layered config per call (matches loadAutopauseConfig).
Disabled → exit 65 with a config-set hint; no host process touched.
- Wired into both `handleIntegrationRpc` (server.ts, docker) and
`runIntegrationRpc` (host-actions.ts, daytona/hetzner/vercel/e2b) per
the "fix across all providers" rule. Order: refuseIntegrationCall
first (op-level), then enablement gate, then readiness probe, then
prompt. Same order on both providers — a malformed-args-to-disabled-
integration call returns the same envelope shape.
Connector cleanup (T1 minimal change)
- packages/integrations/src/connectors/notion.ts: drop `comment.add`.
`ntn` exposes no top-level `comment` subcommand; the only host path
is `ntn api v1/comments -X POST -f …` which the T1 `api` op refuses
(GET-only). No callers exist (T1 just merged), so a forward-only
drop is cleaner than carrying dead surface. The shim refuses
`notion comment add …` with a "deferred from T2" message. Comments
tracked as a focused follow-up (need a Notion-API-aware payload
translator that maps CLI flags to the structured POST body).
- Added `whoami` read op so `ntn whoami` doesn't widen the `api`
allowlist. The connector already declared `api v1/users/me` as the
T3 doctor probe — `whoami` reuses the same auth check via its
dedicated host CLI subcommand.
Tests (vitest, no docker, no network)
- packages/ctl/test/gh-and-shims.test.ts: extended with NTN_SHIM cases
mirroring the gh / git shim patterns.
- packages/config/test/merge-precedence.test.ts +
set-unset-roundtrip.test.ts: cover the new 3-level cascade and the
YAML pruning roundtrip.
- packages/relay/test/integrations.test.ts: workspace agentbox.yaml in
beforeEach now flips the integration on; new tests for the disabled
envelope and the injectable-loader unit shape.
- packages/relay/test/host-actions.test.ts: parity check for the cloud
gate.
Docs
- docs/notion_backlog.md: T2 flipped to done with the comment-handling +
gate-placement decisions and the comments-deferred note.
T3 (doctor + docs site) and T4 (nested-box e2e) remain.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced Jun 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ships T2 of the Notion integration: an in-box
ntn/notionshimmodeled on
gh-shim, image provisioning across all providers(docker / hetzner / vercel / e2b — daytona stays shim-less to match its
T1 gh/git decision), and a typed config flag
integrations.notion.enabled(default off) gated at the relay. The host's authenticated
ntnruns the call; the box never holds a Notion token.
Builds on T1 (PR #73). T3 (doctor + docs site) and T4 (nested-box e2e)
remain.
Decisions called out
comment.adddropped from T1's connector.ntnhas no top-levelcommentsubcommand — the only host path isntn api v1/comments -X POST -f …which the T1apiop refuses (GET-only). There wereno callers (T1 just merged, no shim yet), so a forward-only drop is
cleaner than carrying dead surface. The shim refuses
notion comment add …with a "deferred from T2" message. A focused follow-up willneed a Notion-API-aware payload translator that maps CLI flags to the
structured POST body.
whoamiread op added sontn whoamidoesn't widen theapiallowlist (it reuses the same auth check the connector already
declared as the T3 doctor probe).
refuseIfIntegrationDisabledinpackages/relay/src/integrations.ts), wired into BOTHhandleIntegrationRpc(docker) ANDrunIntegrationRpc(cloud) perthe "fix across all providers" rule. Re-reads the layered config per
call so flipping the flag takes effect without bouncing the relay
(mirrors
loadAutopauseConfig). Disabled → exit 65 with aagentbox config set --project integrations.notion.enabled truehint;no host process is touched.
notionis a symlink tontn, not a separate shim. Bothinvocations behave identically; the
notionname is the per-servicesurface from
docs/integrations_backlog.md.integrations.notion.enabledis natural YAML(
integrations: { notion: { enabled: true } }) — the previous codeonly handled 1-level branch.leaf.
Test plan
pnpm -w typecheckgreenpnpm -w testgreen (487 tests + 1 skipped, including the newshim allowlist, config 3-level cascade + roundtrip, relay docker gate,
cloud gate)
pnpm -w buildgreen; ntn-shim staged into all four providerruntime trees (docker / hetzner / vercel / e2b)
whoami/api/pages create/pages updateroute to ctl;pages list/comment add/login/datasourcesetc. refuse with exit 2 and a clear stderragentbox doctorreporting + the public docssite
Note
Medium Risk
Touches relay integration dispatch and layered config parsing for all providers; mis-wiring could block or accidentally allow Notion RPCs, but defaults stay off and the gate fails closed.
Overview
Adds T2 of the Notion integration: in-box
ntn/notioncommands (strict allowlist shim →agentbox-ctl integration notion …) with the shim baked into docker, Hetzner, Vercel, and E2B images (staging,Dockerfile.box, provider install scripts, andruntime-assets).Introduces
integrations.notion.enabled(default false) in typed config, with parser/merge/write updated for nested dotted keys so YAML can useintegrations.notion.enabled. The relay enforces enablement viarefuseIfIntegrationDisabledon both dockerPOST /rpcand cloudrunIntegrationRpc— exit 65 and a config hint when off, before readiness checks, prompts, or hostntnspawn.Connector cleanup: drops unused
comment.add, adds readwhoami; shim rejects deferred comment flows. Tests cover shim routing, config cascade/roundtrip, and relay gate behavior.Reviewed by Cursor Bugbot for commit 60a484a. Configure here.