Connector reference
This page defines the connector contract: manifest fields, configuration schema, SDK lifecycle, document fields, state, and local validation. For a guided introduction, start with Build a connector.
Manifest
manifest.json declares the connector to Gety. Gety reads the manifest when you install the connector, so manifest changes require reinstalling the connector.
| Field | Required | Description |
|---|---|---|
id | Yes | Stable connector ID. Must match ^[a-z0-9][a-z0-9_-]*$: start with a lowercase letter or digit, then use lowercase letters, digits, _, or -. Do not use uppercase letters, dots, or a leading _ or -. |
name | Yes | Display name shown in Gety's connector list and install dialog. |
version | Yes | SemVer version of the connector. |
min_gety_app_version | Yes | Minimum Gety app version, as SemVer. |
entry | Yes | Relative path to the built entry inside the connector root, usually dist/main.js. |
capabilities | Yes | Non-empty array of host integration points. A polling data source declares ["data-source"], currently the only supported value. Unknown values are rejected. |
description | No | Short description shown in the install dialog. |
author | No | Author object, for example { "name": "Gety" }. |
icon | No | Relative path to a PNG or SVG in the connector root. Gety shows it in the connector list and install dialog. |
schedule | No | Update strategy. If omitted, Gety uses its default interval behavior. See Schedule. |
config | No | Configuration form schema. See Config fields. |
doc_link | No | Declares how documents open. See Doc link. |
schema.extra_gety_indexed_fields | No | Makes extra metadata keys searchable. See Indexed fields. |
entry and icon must stay inside the connector root. Unknown manifest fields are rejected.
Schedule
schedule controls how Gety polls the source.
| Shape | Behavior |
|---|---|
{ "strategy": "manual" } | Gety doesn't poll automatically. Users can still run Update now. |
{ "strategy": "interval", "interval_seconds": 3600 } | Poll every interval_seconds. Values below 60 are clamped to 60. |
{ "strategy": "daily", "time": "09:00" } | Poll once per day at time, using local time. HH:mm and HH:mm:ss are supported. |
Config fields
config.fields is an ordered array. Each field renders an input in Gety's install and configuration UI, and becomes a typed property on this.config.
| Property | Required | Description |
|---|---|---|
id | Yes | Field key. It becomes a property on the generated ManifestConfig type. |
title | Yes | Label shown in the UI. |
type | Yes | Input type. One of text, password, number, checkbox, dropdown, or directory. |
description | No | Helper text shown under the field. |
placeholder | No | Placeholder text for text-like inputs. |
required | No | Whether the field must be filled in. Defaults to false. |
default_value | No | Pre-filled value when the field is empty. The value must match the field type. |
options | For dropdown | Ordered array of { "value": "...", "label": "..." }. |
Field types:
| Type | Use for |
|---|---|
text | Single-line text, such as a URL or username. |
password | API keys and tokens. Values are masked in the UI. |
number | Numeric values. |
checkbox | Boolean on/off options. |
dropdown | A fixed choice from ordered options. |
directory | A local folder path chosen with a picker. |
Use type: "password" for API keys and tokens. For local validation, the sample runner maps field IDs to environment variables. It uppercases the field path and tries the GETY_CONFIG_ prefix first, then the bare name:
api_keyreadsGETY_CONFIG_API_KEYfirst, thenAPI_KEY.auth.api_keyreadsGETY_CONFIG_AUTH_API_KEYfirst, thenAUTH_API_KEY.
Doc link
doc_link declares once, for the whole connector, how documents open.
{ "kind": "url", "field": "url" }
| Property | Description |
|---|---|
kind | url opens a browser link; file opens a local filesystem path. |
field | The doc field or metadata key to read the link value from. |
Resolution rules:
fieldis either a core doc field (id,parent_id,title,content, ordoc_type) or a direct metadata key."field": "url"readsmetadata.url. Use the direct key, not a dot path like"metadata.url".- Missing, empty, or non-string values mean the document has no link.
urllinks open in the browser. Gety doesn't fetch their content.filelinks must be stable local paths, not temporary cache files.
Open, display, and copy actions come from doc_link, not from content_format. content_format only controls how Gety renders the text preview.
Indexed fields
Gety always indexes title and content. schema.extra_gety_indexed_fields makes additional metadata keys searchable. Each entry needs both field and strategy:
{
"schema": {
"extra_gety_indexed_fields": [
{ "field": "status", "strategy": "fast_text" }
]
}
}
| Strategy | Best for |
|---|---|
fast_text | Short values that need exact, substring, fuzzy, or pinyin matching, such as names, tags, folders, or statuses. |
full_text | Longer text that benefits from SQLite FTS5 keyword search, BM25 ranking, and tokenization. |
semantic | Meaningful prose that should match by vector similarity. Requires the embedding model. |
SDK lifecycle
A connector is a default-exported class extending Connector<Config, State>.
import { Connector, type PollResult, del, upsert } from '@gety-ai/connector-sdk';
import type { ManifestConfig } from './gen/manifest.d.ts';
type State = {
cursor?: string;
};
export default class MyConnector extends Connector<ManifestConfig, State> {
async onLoad(): Promise<void> {
// Optional. Runs once in a fresh runtime process before poll().
}
async *poll(): AsyncGenerator<PollResult, void, unknown> {
let cursor = this.lastState?.cursor;
for await (const page of fetchPages(this.config.api_key, cursor, this.signal)) {
yield {
updates: page.items.map((item) => upsert(toDoc(item))),
state: { cursor: page.next_cursor },
};
cursor = page.next_cursor;
}
}
}
| Member | Description |
|---|---|
this.config | Typed configuration injected from Gety's install or configuration form, shaped by config.fields. |
this.lastState | Host-persisted state from the last successful poll progress, or undefined on the first run. |
this.signal | AbortSignal that aborts when the user disables or restarts the connector. Pass it to fetches. |
onLoad() | Optional, may be async. Runs once in a fresh runtime process before poll(). |
poll() | Required async generator. Yields PollResult batches. |
Lifecycle facts:
- Each scheduled poll starts a fresh connector runtime process.
- Class fields don't persist across polls. Use
stateor an explicit on-disk cache for durable data.
WireDoc fields
Build documents with upsert(doc) and remove them with del(id).
upsert({
id: issue.id,
title: issue.title,
content: markdown,
content_format: 'markdown',
doc_type: 'linear:issue',
doc_updated_at: issue.updatedAt,
original_file_size: markdown.length,
metadata: {
url: issue.url,
created_at: issue.createdAt,
status: issue.status,
},
});
| Field | Required | Description |
|---|---|---|
id | Yes | Stable document ID, unchanged across polls. |
title | Yes | Document title. Always indexed. |
content | No | Text Gety indexes and previews. |
content_format | No | plaintext (default) or markdown. markdown enables Markdown rendering in the text preview. It controls rendering, not source type or how the document opens. Use markdown only for real Markdown. |
doc_type | No | Usually <namespace>:<type>, such as linear:issue, for external records. Use file:<ext> only when the document is genuinely file-like and should use file-extension presentation. Don't label an external record as a file just to get Markdown preview; set the real record type and use content_format for rendering. |
doc_updated_at | No | RFC 3339 source update time with Z or an offset. Use the source document's update time, not the indexing time. |
parent_id | No | ID of a parent document for hierarchical relationships. |
hide_from_search | No | Hides the document from search while preserving it for parent or relationship use. |
original_file_size | No | Size in bytes, used for display. |
metadata | No | Arbitrary key/value map. metadata.url is the conventional link target. If present, metadata.created_at must be an RFC 3339 string or the poll fails. Extra keys become searchable through schema.extra_gety_indexed_fields. |
Only id and title are required; other unset fields are dropped from the wire. Gety limits document content to about 10 MB. Emit pages or chunks instead of huge individual documents or metadata blobs.
Poll and state
poll() yields PollResult batches. Each batch carries updates and an optional state checkpoint.
yield {
updates: [
upsert(docA),
upsert(docB),
del(staleId),
],
state: { cursor: page.next_cursor },
};
Rules:
- Checkpoint after updates. The
stateyou yield with a batch should describe progress reached after that batch's updates. It becomeslastStatein the next poll. - Don't advance state early. Never commit state for documents you haven't yielded yet. If a poll fails after a yielded batch, Gety retries from the last committed state.
- Emit deletes from real signals. Call
del(id)only when the source proves the document disappeared or left scope. - Yield at retry-safe boundaries. For remote APIs, yield per page or durable cursor. For local enumerations, yield per retry-safe file or chunk.
- Handle timestamp cursors carefully. Keep enough state to avoid missing updates that share the same timestamp.
- Page or stream the source. Gety can split large output across messages safely, but your connector should still page or stream source data instead of holding everything in memory.
Validation
Run the sample verification task before installing:
deno task verify
verify runs fix, check, test, and build:
fixruns formatting and lint fixes.checkgenerates the config type and type-checks the project.testruns tests.buildwrites the bundled entry loaded by Gety.
You can also run the steps individually:
deno task fix
deno task check
deno task test
deno task build
Exercise the real lifecycle with the local runner:
cp .env.example .env
deno task runner -- --reset-state
deno task runner -- --polls 2
The runner persists incremental state at dev/.runner/state.json. --reset-state ignores it for a clean first poll. Each run writes a snapshot under dev/runs/<timestamp>/:
dev/runs/<timestamp>/
summary.json
state.before.json
state.after.json
updates.json
deletes.json
docs/
0001-<doc_type>__<doc_id>.md
0001-<doc_type>__<doc_id>.json
The content file is .md for content_format: "markdown" and .txt otherwise. It is omitted when the document has no content. The .json sidecar is always written. Inspect the output for stable IDs, expected content, correct metadata.url, RFC 3339 timestamps, deletes, and before/after state behavior.
After editing src/index.ts, run deno task build, then click Restart in Gety to load the new dist/main.js.