Curiosity

Connector Templates

A connector is the code that pulls data out of a source system and into the workspace's graph. Curiosity ships templates for the common shapes (file system, SQL, REST API, popular SaaS apps) so you can start from a working skeleton instead of a blank file.

For the overall architecture see Connectors. For idempotent design see Schema design. For the SDK API see C# SDK and Python SDK.

Where to get the templates

Templates live in the workspace itself. To download:

  1. Sign into your workspace.
  2. Go to API integrations.
  3. Click + New connector → pick a template.
  4. Choose C# or Python at the bottom right of the dialog.
  5. The workspace generates a starter project (zip), pre-filled with the right SDK reference, an ingestion token, and a stub Main that prints the connection check.

If you can't see API integrations, you don't have admin permissions on this workspace.

Available templates

Template Source shape Languages Notes
File system Local or network share C#, Python Walks a directory, uploads files; OCR/STT run automatically.
SQL database PostgreSQL, MySQL, SQL Server C#, Python Uses incremental cursor (updated_at > ?) to fetch only changes.
REST API JSON-over-HTTP C#, Python Generic skeleton with pagination + retry. Customize for each API.
Slack Conversations, channels, users C# Maps messages to Message nodes with Channel/User edges.
Jira Issues, projects, comments C# Issue key is the stable graph key.
ServiceNow Tickets, KB articles, CMDB C# Carries CMDB CIs as device nodes.
Confluence Spaces, pages, comments C# Uses the version number for incremental updates.
SharePoint Sites, lists, files C# Mirrors site permissions onto the file nodes via RestrictAccessTo*.
Email (PST/MBOX) Mail archives C# Built on Curiosity.Library.FileSync.PstIngest.
CSV / Excel Tabular files Python One row → one node, with column → property mapping.

The exact list available depends on your workspace version. Check the API integrations page.

Hello connector — C#

The smallest possible C# connector. Connect, ensure schema, write one node, commit.

using Curiosity.Library;

[Node]
public class Note
{
    [Key]      public string Id      { get; set; }
    [Property] public string Title   { get; set; }
    [Property] public string Body    { get; set; }
    [Timestamp] public DateTimeOffset CreatedAt { get; set; }
}

class Program
{
    static async Task Main()
    {
        using var graph = Graph.Connect(
            endpoint:      "https://workspace.example.com",
            token:         Environment.GetEnvironmentVariable("CURIOSITY_TOKEN")!,
            connectorName: "hello-connector");

        await graph.CreateNodeSchemaAsync<Note>(overwrite: false);

        graph.AddOrUpdate(new Note
        {
            Id        = "note-0001",
            Title     = "Hello from C#",
            Body      = "This is my first connector.",
            CreatedAt = DateTimeOffset.UtcNow,
        });

        await graph.CommitPendingAsync();
    }
}

Run with CURIOSITY_TOKEN=… dotnet run. The note appears in the workspace immediately.

Hello connector — Python

import os
from curiosity import Graph

with Graph.connect(endpoint="https://workspace.example.com",
                   token=os.environ["CURIOSITY_TOKEN"],
                   connector_name="hello-connector") as g:

    g.add_or_update_by_key(
        node_type="Note",
        key="note-0001",
        content={
            "Title":     "Hello from Python",
            "Body":      "This is my first connector.",
            "CreatedAt": "2026-01-01T00:00:00Z",
        },
    )

    g.commit_pending()

Install with pip install curiosity. Run with CURIOSITY_TOKEN=… python hello.py.

Customizing a template

The templates put scaffolding in three places — change each one as your source dictates:

  1. Source-side fetch. Inside the FetchPage(...) / Fetch(...) helper. Replace with your client library.
  2. Mapping. A MapToGraph(...) function turns a source record into one or more AddOrUpdate(...) and Link(...) calls. Keep this pure (no I/O) so you can unit test it.
  3. Loop driver. The outer loop reads a cursor (last-updated timestamp, last-seen page token) and asks the source for changes. Persist the cursor between runs.

Configure ACLs at ingest time

If the source has permissions, mirror them — don't try to bolt them on later.

var team = await graph.CreateTeamAsync("Engineering");
graph.RestrictAccessToTeam(noteNode, team);

See Access control model.

Incremental sync pattern

var lastSync = await ReadCheckpointAsync();             // your own persistence
var page = 0;

while (true)
{
    var batch = await source.FetchChangedAsync(since: lastSync, page: page++, pageSize: 500);
    if (batch.Count == 0) break;

    foreach (var record in batch)
        MapToGraph(graph, record);

    await graph.CommitPendingAsync();
    lastSync = batch.Max(r => r.UpdatedAt);
    await WriteCheckpointAsync(lastSync);
}

The checkpoint must survive process restarts — write it to disk, S3, or a workspace node, not just memory.

Best practices

  • Stable keys. Always use a source-side stable identifier. Never use a generated UUID for the graph key.
  • Idempotency. Re-running the connector should be a no-op for unchanged records. TryAdd / AddOrUpdate are the building blocks.
  • Auto-commit cost. For high-volume jobs, set SetAutoCommitCost(everyNodes: 10_000) so the local queue doesn't grow unbounded.
  • Pause indexing for backfills. PauseIndexing("backfill") before a large initial load and ResumeIndexing("backfill") after — the workspace will rebuild once instead of many small times.
  • Token scopes. Connector tokens should be scoped tightly — write-only on the relevant types, no admin. See Token scopes.
  • Dry-run mode. Use .WithDryRun(true) during development so you can iterate without polluting the graph.

Contributing back

If you build a connector for a system not in the template list, consider opening a PR against the workspace repository (or a parallel "community connectors" repo if your organization maintains one). A well-shaped template:

  • Pure mapping function with unit tests.
  • Cursor-driven loop with checkpointing.
  • ACL handling visible in the template, even if commented out.
  • A README that lists required environment variables.

Where to go next

© 2026 Curiosity. All rights reserved.
Powered by Neko