What it is
A connector is the piece of code that actually performs a real-world action, a HubSpot deal update, a GitHub pull request merge, a Paytm refund, a Slack message, after every governance check upstream (policy evaluation, signal verification, capability binding, execution authorization) has already approved it. Connectors are deliberately dumb: they validate requests, execute one already-authorized operation using an already-resolved credential (Chapter 11), and return a deterministic response. They never evaluate policy, never authorize anything, and never resolve credentials themselves.Why it was built
Every governed action this system can take needs an actual integration with the outside world, and that integration needs to be swappable, testable in isolation, and structurally incapable of bypassing the governance layers above it. TheConnector contract
(packages/connector-sdk/src/ConnectorTypes.ts:157) exists to enforce that boundary in
code, not just in documentation. Its doc comment states that “a Connector never receives a
request directly from the Runtime or AI, only from SdkConnectorExecutor” (ConnectorTypes.ts:152-155),
which in turn is reachable only through the Execution Gateway.
How it works
TheConnector interface itself is small:
ConnectorExecutionContext (ConnectorTypes.ts:85-97) carries a credential (a
CredentialHandle, already resolved by the session credential vault from Chapter 11, not a
raw secret the connector has to go fetch), a timeoutMs, and a requestedAt timestamp. It
also has an optional release field, which the Execution Gateway sets on every governed
release. It names the authorization, the policy identity, and the signed human approvals behind
the release. A connector that forwards the action outside Parmana signs it into that release
(ADR-0013). Every other connector may ignore it.
Each real connector in this codebase splits into two files: a *-Capabilities.ts file in a
dedicated @parmana/connector-{name} package (pure metadata: capability identifier constants
and request/response DTOs, no execution logic at all), and an executable adapter under
packages/execution-gateway/src/connector-execution/Gateway{Name}Adapter.ts that actually
performs the HTTP call. Each capabilities file says so explicitly in its own header comment
(for example HubSpotCapabilities.ts and GitHubCapabilities.ts).
The four live connectors
The policy column comes from the canonical binding table in
packages/capability-registry/src/CapabilityPolicyBinding.ts, the same table Chapter 6 covers.
That file’s own comments say the version in effect is the one most recently approved through
policy governance, so a new policy version takes effect when it is approved. Every policy in
this table needs a signed human approval for the action and its resource, reads included
(Human approval).
HubSpot (packages/connector-hubspot/src/): two capabilities, fetch and update a deal.
HubSpotSignalStateVerifier (a separate file in the same package) checks caller-declared
signals against HubSpot’s own API, rather than trusting the caller’s assertion. This is the
concrete example Chapter 5 (signal-state verification) points to.
GitHub (packages/connector-github/src/): fetch a PR’s state, merge a PR. It authenticates
as a GitHub App. GitHubAppJwt.ts in this package signs the app JWT, and
GitHubAppCredentialProvider.ts (in execution-gateway) exchanges it for an installation
token. The connector does not use a static personal access token.
Paytm (packages/connector-paytm/src/): exactly one capability, paytm:refund, by design.
Its own doc comment says this is deliberate: “There is no paytm:* wildcard and no additional
Paytm capability (charge, payout, settlement query, …) declared here; adding one is a
deliberate, separate milestone, not an incidental side effect of this one”
(PaytmCapabilities.ts:9-14). It is structurally different from the other three in one
respect. Its baseUrl is required (PaytmCapabilities.ts:43), and requests go to a separate
service, the Paytm agent, which the connector calls over HTTP. The wire-level action string that
this service expects, "paytm-refund" (PAYTM_AGENT_WIRE_ACTION, PaytmCapabilities.ts:29), is a
transport-boundary translation only. Parmana’s own capability identity stays "paytm:refund"
everywhere else.
Slack (packages/connector-slack/src/): exactly one capability, slack:post-message. Its
header comment applies the same “no wildcard, deliberate scope” rule as Paytm
(SlackCapabilities.ts:8-13).
Razorpay: a historical case study
A Razorpay connector (RazorpayConnector, RazorpayRefundService,
RazorpaySignalStateVerifier, RazorpayDailyRefundLedger, RazorpayCumulativeRefundLedger,
RazorpaySettlementProcessor, and supporting files) was built, ran in production, and was
removed from this codebase on 2026-08-12, in commit d8a6ded, as recorded in
docs/VERIFICATION-GAPS.md. No Razorpay connector source exists on main today. Three
database tables for it (razorpay_webhook_events, razorpay_webhook_audit_events,
razorpay_daily_refund_reservations) outlived the code. They were dropped by
supabase/migrations/20260916120000_drop_razorpay_tables.sql on 2026-09-16, which describes
them as orphaned after the connector’s removal.
The practical lesson: entries in docs/VERIFICATION-GAPS.md that predate 2026-08-12 and describe
Razorpay-specific mechanisms as wired into production are accurate history, not current fact. The
document carries a stale-narrative notice, added 2026-08-24, that says so.
How to validate this yourself
packages/connector-sdk/src/ConnectorTypes.ts, theConnectorcontract itself.packages/connector-hubspot/src/,connector-github/src/,connector-paytm/src/, andconnector-slack/src/, each connector’s capability metadata and DTOs.packages/execution-gateway/src/connector-execution/Gateway{HubSpot,GitHub,Paytm,Slack}Adapter.ts, the executable adapters.packages/capability-registry/src/CapabilityPolicyBinding.ts, the canonical capability-to-policy table.packages/api/src/bootstrap/createConnectorRegistry.ts, where connectors are registered at startup and where each missing connector logs its*_connector_unavailableevent.assertConnectorCapabilitiesBound.tsin the same directory checks that every declared capability has a canonical policy binding.- Integration tests:
packages/api/tests/integration/hubspot-deal-update.integration.test.ts,github-pr-merge.integration.test.ts, andpaytm-refund.integration.test.ts. Each one is a connector’s HTTP-boundary proof. Hermetic mock servers stand in for vendor APIs:MockHubSpotServer.ts(connector-hubspot),MockGitHubServer.ts(connector-github),MockPaytmConnectorServer.ts(connector-paytm), andMockSlackServer.ts(connector-slack).
Integration requirements
Each connector needs its own credentials configured, only when it is used:- HubSpot:
HUBSPOT_PRIVATE_APP_TOKEN. - GitHub:
GITHUB_APP_ID,GITHUB_INSTALLATION_ID, andGITHUB_APP_PRIVATE_KEY. - Paytm: a
baseUrlpointing at a deployed Paytm agent instance. It is required, with no default. - Slack: see
createSlackConnector.tsfor the exact variable.
createConnectorRegistry.ts logs an *_connector_unavailable event for it
(hubspot_connector_unavailable, github_connector_unavailable, paytm_connector_unavailable,
slack_connector_unavailable), naming the missing configuration.