indykite/skills

indykite-ciq-create-node-with-link

Author an IndyKite ContX IQ (CIQ) policy plus its Knowledge Query that creates a brand-new node AND links it to one or more existing nodes via new relationships in a single `POST /contx-iq/v1/execute` call.

First seen May 19, 2026

Installation

$ npx skills add indykite/skills --skill indykite-ciq-create-node-with-link

Summary

  • Author an IndyKite ContX IQ (CIQ) policy plus its Knowledge Query that creates a brand-new node AND links it to one or more existing nodes via new relationships in a single `POST /contx-iq/v1/execute` call.
  • Use when ingesting a new entity that must be wired into the IKG atomically - combines node creation and relationship creation in one operation.

Also in this package

Other skills from indykite/skills · top by installs.

npx skills add indykite/skills

Browse all from indykite/skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 4
License LICENSE
Default branch main
Open issues 1
Status Active

Skill metadata

Parsed from SKILL.md frontmatter.

LicenseApache-2.0
CompatibilityRequires curl, bash 4+, and jq. Network access to the regional IndyKite REST API (eu.api.indykite.com or us.api.indykite.com) is required at runtime.

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 16,057 B
  • docs SUMMARY.md 392 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 53 installs

SKILL.md

IndyKite ContX IQ - create a new node + link it to existing nodes

Create a brand-new node in the IndyKite Graph (IKG) and wire it to one or more existing nodes in a single atomic POST /contx-iq/v1/execute call. The policy whitelists both a node label and one or more relationship triples, and the Knowledge Query carries both upsertnodes (for the new node) and upsertrelationships (for the new edge(s)); the new node's variable name from upsertnodes is referenced as the source or target in upsertrelationships. It combines the patterns from [indykite-ciq-create-node](../indykite-ciq-create-node/SKILL.md) and [indykite-ciq-create-relationship](../indykite-ciq-create-relationship/SKILL.md).

This is the canonical "ingest a new entity into the graph" pattern - used in the IndyKite developer-hub resources for the insurance Contract example (policyAllowWriteContract + knowledgeQueryAllowWriteContract), where one execute creates a new Contract node and wires it via two relationships (COVERS to a Vehicle, ACCEPTED from a Person).

Other paths are deliberately out of scope:

  • Just creating a node, no link - use [indykite-ciq-create-node](../indykite-ciq-create-node/SKILL.md).
  • Just linking two existing nodes - use [indykite-ciq-create-relationship](../indykite-ciq-create-relationship/SKILL.md).
  • Updating an existing node's properties or relationship's properties - different operations entirely.

When to use

Activate this skill when the user:

  • wants to ingest a new entity through CIQ in one atomic operation (create the node and its relationships to existing nodes);
  • is implementing the canonical insurance/contract pattern: a new Contract node linked to an existing Vehicle and an existing Person;
  • is building an "add a comment to a document" flow: a new Comment node linked to an existing Document;
  • is parameterising both the new node's externalid and the source/target endpoints from inputparams;
  • is debugging a 403 / 422 from a combined create execute that should have wired the new node up.

Do not activate this skill when the user:

  • only needs to create a node - use [indykite-ciq-create-node](../indykite-ciq-create-node/SKILL.md);
  • only needs to link two existing nodes - use [indykite-ciq-create-relationship](../indykite-ciq-create-relationship/SKILL.md);
  • needs to write properties on existing elements - use the property-write skills.

Prerequisites

  • An IndyKite project, AppAgent, and AppAgent credentials.
  • A Service Account token with Config API access, and the project's GID in PROJECT_GID - both used to create the policy and Knowledge Query.
  • The endpoint nodes the new node will link to already in the IKG.
  • The node label and relationship label(s) the operation will use, allowed by the project's data model.
  • A plan for the new node's external_id - usually parameterised via $param.

Steps

1. Pick the subject and the cypher pattern

Subject type - pick one. The schema is identical across both choices; only subject.type, the filter, and the execute-time auth differ:

Subject Use when Auth at execute time Filter convention
_Application System-side / ETL / catalog work; no user in the loop. X-IK-ClientKey only. subject.externalid = $appId (reserved).
Person / User The authenticated user is performing the operation themselves. X-IK-ClientKey + Authorization: Bearer <token>. subject.external_id = $token.sub.

A policy is restricted to a single subject type - if both should be allowed, write two policies. The runnable example below uses _Application (insurance-contract ingestion); a Person variant - for example, a user posting a new Comment linked to an existing Document they own - differs only in subject.type, the filter, and the execute headers.

Cypher pattern - must MATCH the subject and every existing endpoint the new node will link to. The new node itself is not matched; it's declared in upsert_nodes. If the exact node types, relationship types, or property spellings in the project's IKG are unknown, read them from the Data Schema API first ([indykite-data-schema](../indykite-data-schema/SKILL.md)) - a typoed name silently matches nothing, and a write whose pattern matches nothing is a no-op that still returns 200.

Working example (used throughout this skill, taken verbatim from the developer-hub policyAllowWriteContract resource):

An _Application creates a new Contract node and links it via :COVERS to an existing Vehicle (owned by an existing Company) and via :ACCEPTED from an existing Person.

MATCH (subject:_Application)-[r1:HAS_AGREEMENT_WITH]->(company:Company)-[r2:OWNS]->(vehicle:Vehicle)
MATCH (person:Person)

Variables: subject, r1, company, r2, vehicle, person. The new Contract node will be declared as a fresh name in upsert_nodes; the two new relationships will reference vehicle, person, and the fresh name as endpoints.

2. Author the policy with both nodetypes and relationshiptypes

Build the policy JSON with five blocks:

  • meta.policy_version - currently 1.0-ciq.
  • subject.type - _Application for the running example.
  • condition.cypher and condition.filter - the cypher matches the subject and existing endpoints; the filter pins them by externalid ($appId plus $vehicleID, $personID).
  • allowedupserts.nodes.nodetypes - the new node's label (e.g. ["Contract"]).
  • allowedupserts.relationships.relationshiptypes - one triple per new relationship, matching the directions and labels.

A complete combined-create policy for the running example: see [assets/policy-create-contract.json](assets/policy-create-contract.json).

Create it through the Config API:

# set the current project_id, and stringify only the `policy` field, before POSTing
jq --arg pid "$PROJECT_GID" '.project_id = $pid | .policy |= tojson' indykite-ciq-create-node-with-link/assets/policy-create-contract.json \
  | curl -X POST "$API_URL/configs/v1/authorization-policies" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $SERVICE_ACCOUNT_TOKEN" \
      -d @-

A 201 Created returns the policy's id (GID). Export it as POLICYID - the Knowledge Query create injects it into policyid.

For the schema deep-dive (how nodetypes and relationshiptypes interact, why direction matters, what existing_nodes would add) see [references/policy-reference.md](references/policy-reference.md).

3. Create the Knowledge Query with both upsertnodes and upsertrelationships

The Knowledge Query has two write arrays:

upsert_nodes - declares the new node. Same shape as in [indykite-ciq-create-node](../indykite-ciq-create-node/SKILL.md):

  • name - fresh variable name (not in cypher), e.g. contract.
  • type - node label, must match allowedupserts.nodes.nodetypes.
  • external_id - required for new nodes; usually $param.
  • labels - optional array of extra labels attached alongside type. Chiefly used to create identity nodes - see the note below.
  • properties - array of {type, value, metadata?} items.

Identity nodes. The Knowledge Query has no isidentity field - that flag belongs to the Capture API. In the IKG, identity status is carried by the DigitalTwin label; Capture's isidentity: true is shorthand for adding it at ingest. The CIQ equivalent is "labels": ["DigitalTwin"] on the upsertnodes entry. The label goes in labels only - the policy's nodetypes whitelist checks type, so DigitalTwin is never listed there. Create the node as an identity node whenever it must act as a 2.0-kbac subject: a non-identity subject makes every 2.0-kbac decision silently false (3.0-kbac does not require it). To confirm the label landed, run a 2.0-kbac evaluation with the new node as subject.

upsert_relationships - declares each new relationship. Same shape as in [indykite-ciq-create-relationship](../indykite-ciq-create-relationship/SKILL.md), with one important twist:

  • name - fresh variable name for each new relationship (e.g. r3, r4).
  • source - variable name. Can be a cypher variable (existing node) or the name of an upsert_nodes entry (the just-created node).
  • target - same: cypher variable or upsert_nodes name.
  • type - must match the policy's relationship_types.

That source/target flexibility is what makes the combined operation work: r3 connects the just-created contract to the existing vehicle; r4 connects the existing person to the just-created contract.

A complete combined-create Knowledge Query for the running example: see [assets/knowledge-query-create-contract.json](assets/knowledge-query-create-contract.json).

Create it through the Config API:

# set the current project_id and policy_id, and stringify only the `query` field, before POSTing
jq --arg pid "$PROJECT_GID" --arg polid "$POLICY_ID" '.project_id = $pid | .policy_id = $polid | .query |= tojson' indykite-ciq-create-node-with-link/assets/knowledge-query-create-contract.json \
  | curl -X POST "$API_URL/configs/v1/knowledge-queries" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $SERVICE_ACCOUNT_TOKEN" \
      -d @-

A 201 Created returns the Knowledge Query's id (GID).

Schema details (which arrays interact, response shape covering both new nodes and new relationships) live in [references/knowledge-query-reference.md](references/knowledge-query-reference.md).

4. Authenticate and execute

The execute endpoint is the same as for every other CIQ operation:

POST <API_URL>/contx-iq/v1/execute

For the _Application subject:

  • X-IK-ClientKey: <AppAgent-credentials-token> - required.
  • Authorization: Bearer … - omit.

Request:

{
  "id": "<knowledge_query_gid_or_name>",
  "input_params": {
    "vehicleID": "car2",
    "personID":  "ryan",
    "contract_external_id": "ct853",
    "contractNumber":       "rbjh853"
  }
}

A runnable shell helper: [scripts/execute.sh](scripts/execute.sh).

Full execute reference: [references/execution-reference.md](references/execution-reference.md).

5. Verify the response and confirm the wiring

A successful combined-create returns the new node's projection plus the new relationships' identifiers:

{
  "data": [
    {
      "nodes": {
        "contract.external_id":     "ct853",
        "contract.property.number": "rbjh853"
      },
      "relationships": {
        "r3": { "Id": …, "ElementId": "…", "StartId": …, "EndId": … },
        "r4": { "Id": …, "ElementId": "…", "StartId": …, "EndId": … }
      }
    }
  ]
}

If the response is not what you expected, walk this list:

  1. Both whitelist entries present. The KQ's upsertnodes[].type must be in allowedupserts.nodes.nodetypes, and each upsertrelationships[] triple must be in allowedupserts.relationships.relationshiptypes. Either mismatch → 403.
  2. Endpoints exist. Every cypher variable the relationships reference (vehicle, person) must resolve to a real node. If MATCH finds no rows, the operation has nothing to wire - 200 with empty data.
  3. Cross-references match. The new node's name in upsertnodes (e.g. contract) must be exactly the same string used in upsertrelationships[].source or target. Typos here silently produce wiring failures.
  4. Direction matches. Relationship triples encode direction. (Contract)-[:COVERS]->(Vehicle) is different from (Vehicle)-[:COVERS]->(Contract).
  5. All $params present. The contractexternalid, contractNumber, vehicleID, personID all need to be in input_params.

For other failure modes see [references/troubleshooting.md](references/troubleshooting.md).

Outcome

When this skill has been applied successfully:

  • A combined-create CIQ policy exists; it has a single subject.type, a Cypher pattern matching the subject and existing endpoint nodes, partial filters, and both allowedupserts.nodes.nodetypes and allowedupserts.relationships.relationshiptypes populated.
  • A Knowledge Query references the policy and lists the new node in upsertnodes and one or more new relationships in upsertrelationships (with the new node's name referenced as a source or target).
  • One POST /contx-iq/v1/execute returns the new node's projection plus the new relationships' identifiers.
  • A follow-up read confirms the new entity is wired into the graph.

Files in this skill

  • [references/policy-reference.md](references/policy-reference.md) - combined nodetypes + relationshiptypes, optional existing_nodes for hybrid create-and-update flows.
  • [references/knowledge-query-reference.md](references/knowledge-query-reference.md) - upsertnodes + upsertrelationships interaction, source/target cross-referencing, identity nodes via labels, multi-relationship patterns.
  • [references/execution-reference.md](references/execution-reference.md) - request/response, atomicity guarantees, idempotence on rerun.
  • [references/troubleshooting.md](references/troubleshooting.md) - 403 / empty-data / wiring-mismatch / cross-reference patterns.
  • [assets/policy-create-contract.json](assets/policy-create-contract.json) - the canonical insurance-Contract example, lifted from policyAllowWriteContract in the developer-hub resources.
  • [assets/knowledge-query-create-contract.json](assets/knowledge-query-create-contract.json) - matching Knowledge Query.
  • [scripts/execute.sh](scripts/execute.sh) - Bash helper.

Agent-specific notes

This skill uses generic markdown instructions and works across all agents listed in the [README](../README.md). The agent needs to be able to issue HTTP requests. No Claude Code hooks, Cursor @-mentions, or Copilot workspace context are required.

References