WR

writing-hashql-jexpr

Reference and syntax guide for HashQL J-Expr to define paths, function calls, and data structures in .jsonc query files.

Install

mkdir -p .claude/skills/writing-hashql-jexpr && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/2726" && unzip -o skill.zip -d .claude/skills/writing-hashql-jexpr && rm skill.zip

Installs to .claude/skills/writing-hashql-jexpr

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

HashQL J-Expr syntax for writing queries. Use when writing J-Expr code, using #literal/#struct/#list constructs, understanding function call syntax, or working with HashQL query files (.jsonc).
193 chars✓ has a “when” trigger
Advanced

Key capabilities

  • Represent typed expressions using JSON primitives
  • Construct data using #literal, #struct, #list, #tuple, #dict
  • Define function calls as arrays
  • Map strings to paths or identifiers
  • Apply type annotations with #type

How it works

J-Expr uses JSON structures where strings represent paths, arrays represent function calls, and objects with specific # keys act as data constructors. It enforces strict typing by requiring primitives to be wrapped in #literal objects.

Inputs & outputs

You give it
HashQL query file (.jsonc)
You get back
Parsed J-Expr expression tree

When to use writing-hashql-jexpr

  • Writing HashQL query expressions
  • Parsing J-Expr syntax
  • Constructing JSONC query files

About this skill

Writing HashQL J-Expr

J-Expr is a JSON-based expression syntax for HashQL. It represents typed expressions using JSON primitives.

Expression Types

J-Expr has three expression types:

JSON TypeJ-Expr Meaning
StringPath/identifier/symbol
ArrayFunction call
ObjectData constructor (with # keys)

Paths (Strings)

Strings are parsed as paths or identifiers:

"x"                           // Simple variable
"vertex.id.entity_id"         // Dotted path access
"::core::types::String"       // Namespaced/rooted path
"::graph::head::entities"     // Graph function path

Function Calls (Arrays)

Arrays represent function calls: [function, arg1, arg2, ...]

// Basic function call
["add", {"#literal": 1}, {"#literal": 2}]

// Namespaced function
["::graph::head::entities", ["::graph::tmp::decision_time_now"]]

// Labeled argument with :prefix in object
["greet", {":name": {"#literal": "Alice"}}]

// Shorthand labeled argument (string with :prefix)
["func", ":name"]

Data Constructors (Objects with # Keys)

Objects with special # keys construct data:

KeyPurposeExample
#literalPrimitive values{"#literal": 42}
#structNamed fields{"#struct": {"x": ...}}
#listVariable-size ordered{"#list": [...]}
#tupleFixed-size ordered{"#tuple": [...]}
#dictKey-value map{"#dict": {"k": ...}}
#typeType annotationUsed with other keys

Literals

{"#literal": 42}
{"#literal": "hello"}
{"#literal": true}
{"#literal": null}
{"#literal": 3.14, "#type": "Float"}

Struct

{"#struct": {"name": {"#literal": "Alice"}, "age": {"#literal": 30}}}
{"#struct": {"x": {"#literal": 1}}, "#type": "Point"}

List and Tuple

{"#list": [{"#literal": 1}, {"#literal": 2}]}
{"#tuple": [{"#literal": 1}, {"#literal": "text"}]}

Dict

{ "#dict": { "key": { "#literal": "value" } } }

Common Patterns

Let Binding

["let", "varName", { "#literal": 10 }, ["add", "varName", { "#literal": 5 }]]

Function Definition

["fn", {"#tuple": []}, {"#struct": {"vertex": "_"}}, "_", body_expr]

Conditionals

["if", condition_expr, then_expr, else_expr]

Comparison

["==", "left", "right"]
[">", {"#literal": 5}, {"#literal": 3}]

Do

  • Use #literal for all primitive values (numbers, strings, booleans, null)
  • Use :: prefix for namespaced paths
  • Use : prefix for labeled arguments
  • Combine #type with other constructors for type annotations

Don't

  • Don't use bare JSON numbers/booleans - wrap in {"#literal": ...}
  • Don't confuse #list (variable-size) with #tuple (fixed-size)
  • Don't use # prefix for labeled arguments (use :)
  • Don't nest # keys incorrectly - each object should have one primary # key

Examples

Entity query:

["::graph::head::entities", ["::graph::tmp::decision_time_now"]]

Filtering with comparison:

[
  "filter",
  "entities",
  [
    "fn",
    { "#tuple": [] },
    { "#struct": { "entity": "_" } },
    "_",
    ["==", "entity.draft_id", { "#literal": null }],
  ],
]

Struct with type:

{ "#struct": { "value": { "#literal": 100 } }, "#type": "Amount" }

References

  • Syntax Reference - Paths, function calls, operators
  • Special Forms - Language constructs (if, let, fn, type, use, etc.)
  • Data Constructors - Typed data (#literal, #struct, #tuple, #list, #dict, #type)
  • Type DSL - Embedded type annotation syntax
  • Parser: libs/@local/hashql/syntax-jexpr/src/parser/
  • Object forms: libs/@local/hashql/syntax-jexpr/src/parser/object/
  • Type DSL: libs/@local/hashql/syntax-jexpr/src/parser/string/type.rs

When not to use it

  • When writing standard JSON without HashQL requirements
  • When using bare JSON numbers or booleans

Limitations

  • Requires wrapping all primitives in #literal
  • Strict distinction between #list and #tuple

How it compares

It provides a structured, typed expression syntax for JSON-based queries compared to writing raw, untyped JSON objects.

Compared to similar skills

writing-hashql-jexpr side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
writing-hashql-jexpr (this skill)22moNo flagsAdvanced
backend-development174moNo flagsIntermediate
laravel-specialist123moNo flagsIntermediate
supabase-python04moReviewAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

More by hashintel

View all by hashintel

handling-rust-errors

hashintel

HASH error handling patterns using error-stack crate. Use when working with Result types, Report types, defining custom errors, propagating errors with change_context, adding context with attach, implementing Error trait, or documenting error conditions in Rust code.

46

exploring-rust-crates

hashintel

Generate Rust documentation to understand crate APIs, structure, and usage. Use when exploring Rust code, understanding crate organization, finding functions/types/traits, or needing context about a Rust package in the HASH workspace.

33

documenting-rust-code

hashintel

Rust documentation practices for HASH codebase. Use when writing doc comments, documenting functions/types/traits/modules, creating error sections, using intra-doc links, or following rustdoc conventions.

19

managing-cargo-dependencies

hashintel

Cargo.toml dependency management patterns for HASH workspace. Use when adding, updating, or removing dependencies, organizing Cargo.toml sections, configuring version pinning and default features, or managing public dependencies.

13

managing-git-workflow

hashintel

Git workflow for HASH including branch naming, PR creation, and PR reviews. Use when creating branches, making commits, opening pull requests, or reviewing PRs.

12

testing-hashql

hashintel

HashQL testing strategies including compiletest (UI tests), unit tests, and snapshot tests. Use when writing tests for HashQL code, using //~ annotations, running --bless, debugging test failures, or choosing the right testing approach.

11

Search skills

Search the agent skills registry