From lynk-semantic-layer
Inspect the Lynk data catalog via the API, reconcile entity YAMLs when source columns change, and execute ad-hoc Lynk SQL against the semantic layer: list registered schemas, list sources (tables), fetch a source's columns, sync the catalog against the warehouse, clean up entity field features whose source columns were dropped, and run Lynk SQL queries. Use this skill whenever the user asks to: list schemas, see what tables/ schemas exist, model a new table (fetch its columns first), sync sources, refresh source columns after a warehouse schema change, clean up entity fields after a source update, or run / test a Lynk SQL query. Trigger phrases: "list schemas", "what schemas do I have", "add the orders table", "sync sources", "I added fields to orders", "the source columns changed", "what fields does the orders table have", "clean up after the inquiries table dropped column referrer_id", "run this query", "test this SQL", "does this lynk SQL execute". This skill is read-and-API-only on the catalog side. It hands off to `lynk-build` for any `.yml` edits it surfaces (e.g., removing field features whose source column was dropped).
How this skill is triggered — by the user, by Claude, or both
Slash command
/lynk-semantic-layer:lynk-sourcesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill owns the warehouse-facing workflow: it lists schemas and sources, fetches a source's columns, syncs the catalog, reconciles entity YAMLs when source columns change, and runs ad-hoc Lynk SQL against the semantic layer. Other skills delegate to it whenever they need the warehouse side of the layer — `lynk-build` calls it before modeling a new table and to validate that referenced colum...
This skill owns the warehouse-facing workflow: it lists schemas and sources, fetches a source's columns, syncs the catalog, reconciles entity YAMLs when source columns change, and runs ad-hoc Lynk SQL against the semantic layer. Other skills delegate to it whenever they need the warehouse side of the layer — lynk-build calls it before modeling a new table and to validate that referenced columns exist; lynk-evaluate calls it when checking Lynk SQL against the live engine. The data-catalog REST API is the transport; the workflow logic (reconcile flow, hand-off to lynk-build when columns drop, SQL execution) is what makes this a skill rather than a thin API wrapper.
Classify the user's request to one of these actions:
| User intent | Action | Method | Route |
|---|---|---|---|
| "list schemas", "what schemas do I have" | List schemas | GET | integrations/data/schemas |
| "list tables", "list sources", "what tables do I have" | List sources | GET | data-catalog/sources |
| "what fields does X have", "show me the columns of X" | Fetch source fields | GET | data-catalog/sources/<id> |
| "sync sources", "the columns changed", "I added fields to X", "add the orders table" | Sync sources | POST | data-catalog/sources/sync |
| "X dropped column Y, clean up the entity" | Reconcile entity | — | combo: sync + fetch fields + hand off to lynk-build |
| "run this SQL", "test this query", "does this lynk SQL execute", "paste a SQL and run it" | Run Lynk SQL | POST | query-engine/query |
Routes above are bare — no /api/ prefix, no leading /. The script prepends /api/ itself, and a leading / gets mangled into a Windows path by Git Bash. references/rest-api.md shows full path-prefixed forms for documentation only — never pass those to the script.
If unclear, use AskUserQuestion to disambiguate. Note: a schema is a DB.SCHEMA scope (e.g., MAINDB.PUBLIC); a source is a single table inside that scope, with id = DB.SCHEMA.TABLE (e.g., MAINDB.PUBLIC.ORDERS).
If .env does not have LYNK_API_TOKEN set, run:
! "$(command -v python3 || command -v python)" "${CLAUDE_PLUGIN_ROOT}/scripts/lynk_api.py" --print-setup
Always invoke the script with its absolute path via ${CLAUDE_PLUGIN_ROOT} — the script lives inside the plugin's install dir, not the user's repo, so a bare scripts/lynk_api.py won't resolve. The "$(command -v python3 || command -v python)" prefix picks whichever Python interpreter the user has, since some envs ship only one of the two binary names.
Ask the user via AskUserQuestion: Set up the token now (relay the script output, ask user to paste token in chat, then LYNK_API_TOKEN='<paste>' "$(command -v python3 || command -v python)" "${CLAUDE_PLUGIN_ROOT}/scripts/lynk_api.py" --save-token) or Skip (exit with Operation not performed — no API token configured.).
Use the method and route from the table in Step 1 — exactly as written, with no /api/ and no leading /. Add --env dev if the user said "on dev". Branch and domain are resolved by the script (current git branch, default domain) — pass --branch or --domain only to override.
! "$(command -v python3 || command -v python)" "${CLAUDE_PLUGIN_ROOT}/scripts/lynk_api.py" <METHOD> <route>
Concrete examples:
! "$(command -v python3 || command -v python)" "${CLAUDE_PLUGIN_ROOT}/scripts/lynk_api.py" GET data-catalog/sources
! "$(command -v python3 || command -v python)" "${CLAUDE_PLUGIN_ROOT}/scripts/lynk_api.py" GET data-catalog/sources/ANALYTICS.LYNK_VIEWS.ORDERS
! "$(command -v python3 || command -v python)" "${CLAUDE_PLUGIN_ROOT}/scripts/lynk_api.py" POST data-catalog/sources/sync
Run Lynk SQL uses --data to pass the query — the body must be a JSON-encoded string, not an object. Single-quote the outer shell argument so the inner double quotes survive intact:
! "$(command -v python3 || command -v python)" "${CLAUDE_PLUGIN_ROOT}/scripts/lynk_api.py" POST query-engine/query --data '"SELECT lead_id FROM lead LIMIT 1"'
For queries that span lines or contain special characters, write them to a file first and use --data-file:
! printf '%s' '"SELECT c.country_name, METRIC('"'"'fm_ngr'"'"') AS fm_ngr FROM activity_agg_daily a JOIN country c ON c.country_code = a.country_id WHERE a.created_date >= '"'"'2026-01-01'"'"' GROUP BY 1 LIMIT 1"' > /tmp/q.json
! "$(command -v python3 || command -v python)" "${CLAUDE_PLUGIN_ROOT}/scripts/lynk_api.py" POST query-engine/query --data-file /tmp/q.json
If you don't know the request/response schema for the chosen route, read references/rest-api.md in this repo — that is the canonical endpoint reference for these skills. Do not fetch the public docs site for API details; the REST API spec is intentionally not published there.
<key_source> (used by the fetch-fields and per-source routes) is the id field returned by the list-sources call (format: DB.SCHEMA.TABLE).
The script prints {url, method, env, branch, domain, status_code, body}. Present results to the user concisely. When you need field-level detail and the action table didn't fully cover it, read the relevant section of references/rest-api.md.
DB.--query page=N for further pages. For large tenants, filter client-side by what the user asked about.description, the catalog keys, the column count, and the column list; this is the canonical truth for that source. The description, keys, and count are what lynk-build needs to ground a new model and choose the entity key (lynk-build Step 5), so surface them, not just the columns. An empty keys: [] means the catalog knows of no primary key — call that out, since it drives lynk-build's key-verification loop.fieldsDeleted > 0, recommend the reconcile flow (Step 5) before further modeling. If sourcesCreated > 0 or the sync added new fields to an existing source, actively offer to model the new content via lynk-build using AskUserQuestion — don't just report it as informational. List the new sources / columns explicitly so the user can pick which to model now. If the user said "add the orders table", treat that as standing consent to model immediately and hand the column list off to lynk-build.200, show row count and the first few rows; offer to show metadata.query_metadata.rendered_sql (the warehouse SQL the engine emitted) and semantics_used (which entities / features / metrics / relationships the engine resolved) when the user is debugging why a query returned what it did. On 422, parse detail: if it's an array (FastAPI input error), the body shape was wrong — verify you JSON-encoded the SQL string; if it's an object with error_type: SemanticsConsumptionError, surface the message verbatim and point the user at the entity / feature it names. On 500, parse detail.error_type: InternalError with SQL error: ParserError(...) is a Lynk-SQL syntax issue (quote the parser message); a bare "Request failed" string with no detail envelope means the branch's semantic layer is in a broken state — recommend running lynk-validate on the same branch before retrying.lynk-validate Step 4 token-handshake (--print-setup, --save-token).<key_source> — that id isn't in the list-sources response; the user may need to sync first.If the response shape is unexpected, show the raw body and ask how to proceed instead of guessing.
When source columns change in the warehouse, entity YAMLs that reference them silently break — field features whose expression points at a dropped column will fail at query time, formula features that depend on those fields will cascade, and metrics that aggregate over them will produce wrong results. This step closes that gap: detect the drift, walk the dependency tree, and hand the cleanup to lynk-build.
When the user said "I added/updated fields to X", "columns changed", or asked to clean up after a dropped column:
body.fieldsDeleted > 0 you definitely need to reconcile; if 0 you may still want to surface added fields.! grep -lrE "key_source:\s*<id>|source:\s*<id>" .lynk/
columns[] against the entity's field features. Build a dependency tree of what each removed column impacts:
expression references the removed column.lynk-build using AskUserQuestion (e.g., "3 new columns appeared in inventory: restock_eta, supplier_tier, is_clearance. Model them now as features? Yes / Defer / Skip the boolean"). Don't just report new columns as informational — the user came here because of a source change, so offering to close the loop is the natural next step.lynk-build to execute the YAML edits. Do not write .yml from this skill. Build's own Step 8 will then run lynk-evaluate to surface any remaining issues.lynk-build.npx claudepluginhub lynk-ai/build-agent --plugin lynk-semantic-layerSearches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Implements vector databases with Pinecone, Weaviate, Qdrant, Milvus, pgvector for semantic search, RAG, recommendations, and similarity systems. Optimizes embeddings, indexing, and hybrid search.