Skip to content
cccskills
FreePublished on GitHub

kortix-connectors

Find and call external service actions through Kortix connectors, choosing the appropriate connected account. Use the CLI for agent tasks or the TypeScript SDK for reusable workflows, with third-party credentials handled by the gateway.

OriginalShow the original description

Use Kortix connectors to reach external systems from a session, an App, a Convex backend, or an external program. Use the `kortix connectors` CLI for agent work, `@kortix/sdk` for durable TypeScript workflows and for App, backend, and script code, and the hosted Kortix MCP server (`<api>/v1/mcp`) for an MCP client outside Kortix. Load this skill to inspect, add, connect, or call external tools without exposing third-party credentials to the sandbox, an App, or a backend.

Works withSlackGmail
See how to install

Good for

  • Finding available external service actions
  • Choosing among connected accounts
  • Adding a service connection
  • Building reusable workflows across external systems

Files included (2)

  • SKILL.md12.9 KB
  • references/sdk.md10.6 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

<skill name="kortix-connectors"> <overview> A **connector** defines tools against an external system. A connector is **not** an account: one connector (e.g. Gmail) can hold several **accounts** — each one SHARED with the whole project or PRIVATE to one member. A **connector call** invokes one tool AS one account.

Use the kortix connectors CLI for normal agent work:

  • kortix connectors ls lists connectors and actions (an ACCOUNTS column shows how many each holds).
  • kortix connectors discover "<intent>" searches visible actions.
  • kortix connectors show <connector>.<action> shows one input schema and risk.
  • kortix connectors accounts <slug> lists the accounts a connector holds, default first — see Choosing the account below before your first call on a connector you have not used yet.
  • kortix connectors call <connector> <action> '<json>' [--account <label>] invokes one action. Every successful result echoes account: say which one ran when it matters.
  • kortix connectors call … --reason "<what this does>" tells the human what the call does if a policy holds it for approval. The approver sees it next to the real arguments. Always pass it on a write whose args are only ids — send_draft (say who it goes to, the subject, and the body), a delete (say what gets deleted), a merge. Without it the approver sees only draft_id. A gated call returns approval_url: share it, then stop the turn. The human's decision, and any message they add to it, arrives as your next prompt — a deny with a message is an instruction, not a dead end. In a Slack or Teams session Kortix posts an approval card in the thread itself (approval_instructions says so): do not repost the link, just stop.
  • kortix connectors call … --attach <file> attaches a file (see Attach files below). Never put base64 in args.
  • kortix connectors call … --out <file> writes the full JSON result to <file> and prints only saved_to, bytes, and shape (keys, array lengths, pageInfo). Use it for list and search calls; tool output above ~50 KB is truncated. Then query the file with jq or bun, never cat.
  • kortix connectors add, rm, and connect manage connectors and connections.

Durable TypeScript workflows use @kortix/sdk and createKortix. Every call runs through the connector gateway. The gateway resolves credentials, enforces access and policy, invokes the upstream system, and records an audit event. The sandbox carries KORTIX_TOKEN; it does not carry raw third-party credentials. </overview>

<when-to-load> Load this skill when the user wants to:
  • Act in an external app or API.
  • Inspect available connectors, actions, or connected computers.
  • Add or configure a connector or connection.
  • Request connector credentials without exposing the value.
  • Build a repeatable workflow that calls external systems.

Do not load it for work that stays inside the local repository or sandbox. </when-to-load>

<choosing-the-account> **A connector is not an account.** One connector (e.g. Gmail) can hold many accounts — shared with the whole project, or private to one member. Never assume "one connector, one account", and never infer which accounts exist from a `get_profile`/`whoami`-style call: that only ever answers for the ONE account it happened to run as. If a human asks which or how many accounts are connected, list them — do not guess from a profile call.

Procedure, every time you call a connector you have not just listed accounts for:

  1. List the accounts: kortix connectors accounts <slug> (default first; (pinned default) marks the one an unnamed call uses).
  2. One account → just call. Nothing to choose.
  3. Several accounts, and the human named one → pass --account <label|id|me|project> (me = your own private default, project = the shared default).
  4. Several accounts, and it is unclear which one → ASK the human. Do not guess, and do not silently use the default — several real accounts exist and picking wrong sends the action to the wrong mailbox/workspace. If nothing is named and nothing is pinned, the call is refused anyway with reason account_required rather than guessing; a human can pin one going forward with kortix connectors accounts <slug> --default <label>.

Always report which account ran when it could matter — read it off the result's account field, never assume.

Worked example. A project has one Gmail connector (gmail-ffiod0) with two accounts:

$ kortix connectors accounts gmail-ffiod0

  LABEL                 OWNER    DEFAULT  CONNECTION ID
  personal@example.com  private  no       11111111-…
  work@example.com      private  no       22222222-…

  kortix connectors call gmail-ffiod0 <action> --account "personal@example.com"
  kortix connectors call gmail-ffiod0 <action> --account "work@example.com"
  kortix connectors call gmail-ffiod0 <action> --account me
  kortix connectors call gmail-ffiod0 <action> --account project

  2 accounts
  No default pinned — unnamed calls will be refused with account_required;
  pass --account or pin one: kortix connectors accounts gmail-ffiod0 --default <label>

Neither account is pinned, so — asked "check my gmail" with no account named — the right move is to ASK which mailbox, not to call get_profile on whichever account resolves first and report "one account connected". If the human says "the work one", call with --account "work@example.com" and report: "Checked work@example.com — …".

Adding another account. When the human wants a new one ("connect my other Gmail"), mint a link with a --label that tells it apart: kortix connectors connect <slug> --label "Personal Gmail". The link opens a dialog where the human names the account and chooses who can use it; you are then told its name. Call it with --account "<name>" from then on. </choosing-the-account>

<cli-first-loop> Use the CLI first. It is pre-authenticated in a session sandbox.
  1. List visible connectors:
kortix connectors ls
  1. Search by intent:
kortix connectors discover "send an email"
  1. Inspect one action before an unfamiliar call:
kortix connectors show email_email_inbox_bjgk.reply_message
  1. Call the action:
kortix connectors call email_email_inbox_bjgk reply_message \
  '{"inbox_id":"email-inbox@agentmail.to","message_id":"<message-id>","text":"Reply text"}'

Attach files. Write the file under /workspace/artifacts (or output, reports, deliverables), put the JSON args in a file, and pass --attach. The CLI stages the raw bytes and the gateway builds the provider's attachment item (Microsoft Graph, SendGrid, Postmark, Mailjet, Resend, Brevo, and the Email channel):

cat > /tmp/mail.json <<'JSON'
{"user":"sender@example.com","body":{"message":{"subject":"Report",
 "body":{"contentType":"Text","content":"Attached."},
 "toRecipients":[{"emailAddress":{"address":"to@example.com"}}]},
 "saveToSentItems":true}}
JSON
kortix connectors call microsoft-graph sendmail @/tmp/mail.json \
  --attach /workspace/artifacts/report.pdf

Leave the attachments array out of the JSON; --attach appends to it. For a field the CLI cannot find, run kortix connectors upload <file> --connector <slug> and put the printed ref ({"$kortix_attachment":"<id>"}) where the file belongs: in an attachments array, or as the value of a base64 field such as contentBytes. Pass the body as a JSON object, never as a string.

For GraphQL actions, put selected fields in args.__select:

kortix connectors call internal_graph query.user \
  '{"id":"1","__select":"id name email"}'
</cli-first-loop> <sdk-workflows> Use `@kortix/sdk` for dependent calls, pagination, branching, retries, or reusable scripts. Read `references/sdk.md` for the full pattern.
import { createKortix } from '@kortix/sdk';

const kortix = createKortix({
  backendUrl: process.env.KORTIX_API_URL!,
  getToken: async () => process.env.KORTIX_TOKEN ?? null,
});
const connectors = process.env.KORTIX_PROJECT_ID
  ? kortix.project(process.env.KORTIX_PROJECT_ID).connectors
  : kortix.connectors;

const matches = await connectors.search('send an email', { limit: 5 });
const action = await connectors.describe(matches[0]!.tool);
if (!action) throw new Error('Email action not found');

const result = await connectors.call('email_email_inbox_bjgk.reply_message', {
  inbox_id: 'email-inbox@agentmail.to',
  message_id: '<message-id>',
  text: 'Reply text',
});

if (!result.ok) {
  throw new Error(`Connector call failed: ${result.reason ?? result.status ?? 'unknown'}`);
}

Run repository scripts with bun run path/to/script.ts. Keep provider credentials out of code and repository files. </sdk-workflows>

<from-apps-and-backends> App, Convex backend, and external-program code calls connectors through `@kortix/sdk` too. Never give that code a provider API key when a connector for the provider exists: a raw key skips policy, approvals, and audit. The Kortix credential decides which accounts a call reaches:
Where the code runsCredentialReaches
App, browserbackendUrl: '/_kortix/api/v1' + kortixAppViewerToken() (App set to --viewer api)the viewer's shared and private accounts
App, servercreateAppViewerKortix(request, { backendUrl })the same, per request
Convex action, App job with no viewera service account bearer (kortix_sa_…) in an env varshared accounts nobody narrowed; never a private one
External program, CIa personal access token, kortix tokens new <name> --project <id>the token owner's shared and private accounts

A service account is a human step. An agent session cannot create one. Ask the person to run kortix tokens service-accounts new <name> and kortix access grant --service-account <id> --role member --project <id>, and to store the bearer (npx convex env set KORTIX_API_KEY … for Convex; a project secret mapped under apps.<slug>.secrets for an App, with a name that does not start with KORTIX_). Build the rest while you wait. Recipes and errors: references/sdk.md → "Calling from an App, a backend, or a script". </from-apps-and-backends>

<adding-connectors> Connector definitions live in `kortix.yaml`. Connections remain server-side.
connectors:
  - slug: stripe
    name: Stripe API
    provider: openapi
    spec: https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json
    auth:
      type: bearer

Use composio for managed SaaS apps. Other supported direct providers are mcp, openapi, postman, graphql, and http. Add and connect a Composio toolkit with:

kortix connectors add github --provider composio --app github --apply
kortix connectors connect github

Pipedream exists only for rollback compatibility with already-declared connectors. Never add a new Pipedream connector automatically. If Composio cannot satisfy the request, stop, explain the gap, and ask the human before any explicit --allow-legacy-pipedream retry.

Surface the returned connection URL. For an API key you already have (the user gave it in chat), store it now: kortix secrets set NAME=- --scope connector. For one you lack, use kortix secrets request NAME --scope connector.

Slack uses the channel flow. Do not add a Slack connector. Run:

kortix channels connect
</adding-connectors> <rules> - A connector is not an account. One connector (e.g. Gmail) can hold many accounts (shared or private) — see **Choosing the account** above. - If the human asks which or how many accounts are connected, ALWAYS list them with `kortix connectors accounts <slug>`. Never infer accounts from a profile/whoami call. - Use `kortix connectors` for one-off agent actions. - Use `@kortix/sdk` for durable or testable workflows, and for App, Convex backend, and external-program code (see **From apps and backends**). - Use Composio for every new managed SaaS connector. Never select Pipedream unless the human explicitly approves the legacy rollback path. - Do not use raw provider tokens from the sandbox. - Treat `denied`, `not_shared`, `needs_auth`, `account_required`, and `ok: false` as real outcomes — `account_required` means several accounts are reachable and none was named or pinned; pass `--account` or ask the human, do not retry blind. - Report which account ran when it could matter — read the result's `account` field, never assume. - Confirm irreversible work before a destructive connector call. </rules> </skill>

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

access-policy

FreeSummary

Review Slack access requests against Okta role and team information, then prepare narrowly scoped GitHub or AWS IAM permissions. Apply changes only after an eligible person's approval and record the grant, reasoning, approver, and timestamp.

  • Reviewing GitHub repository access requests from Slack
  • Preparing AWS IAM permissions for a specific task
  • Routing sensitive access requests for additional review
kortix-ai/suna20.3KUpdated Oct 22, 2026

account-research

FreeSummary

Research companies and people before outreach or meetings. Combines business profiles, recent news, hiring signals, and key contacts into a sourced brief with talking points and suggested questions, adding relationship history when CRM data is connected.

  • Research a prospective customer before outreach
  • Prepare background information for meeting attendees
  • Compare a competitor's products and positioning
kortix-ai/suna20.3KUpdated Oct 22, 2026

Review daily Google Ads and Meta Ads results for budget pacing, declining performance, and unusual activity. Get prioritized findings with supporting numbers and concrete recommendations for a marketing team to assess and carry out.

  • Checking whether campaign budgets are being spent on schedule
  • Investigating rising acquisition costs or falling ad returns
  • Finding ads and keywords that spend without converting
kortix-ai/suna20.3KUpdated Oct 22, 2026

agent-browser

FreeSummary

Automate website tasks such as navigating pages, filling forms, clicking buttons, taking screenshots, and extracting data. The skill also supports web app testing, with specialized guides for Electron desktop apps, Slack, and cloud browsers.

  • Automate form entry and page navigation
  • Capture screenshots and extract page data
  • Explore web apps for bugs
kortix-ai/suna20.3KUpdated Oct 22, 2026

ap-invoice-match

FreeSummary

Process emailed vendor invoices by extracting details, comparing them with purchase orders and invoice history, and recording duplicates, overcharges, or missing orders. Summarize results in Slack for human review; payment approval and execution remain with people.

  • Checking incoming invoices against purchase orders
  • Finding duplicate invoices and likely resends
  • Reviewing unit prices and remaining order balances
kortix-ai/suna20.3KUpdated Oct 22, 2026

billing

FreeSummary

Guide changes to Kortix billing code, admin controls, and pricing screens. Explain how plans, trials, enterprise contracts, and access exceptions should work, where pricing is defined, and which audited routes must handle account changes.

  • Update billing logic and its specification together
  • Review how trials and enterprise contracts are handled
  • Find the code that defines prices and allowances
kortix-ai/suna20.3KUpdated Oct 22, 2026

See all skills by kortix-ai

Report a problem with this skill