# Writing Hashql Jexpr

> 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).

- Skill: `hashintel/writing-hashql-jexpr` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add hashintel/writing-hashql-jexpr`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hashintel/writing-hashql-jexpr/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: AGPL-3.0
- Author: hashintel (https://skillmd.com/u/hashintel)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/hashintel/writing-hashql-jexpr

---


# 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 Type | J-Expr Meaning                   |
| --------- | -------------------------------- |
| String    | Path/identifier/symbol           |
| Array     | Function call                    |
| Object    | Data constructor (with `#` keys) |

## Paths (Strings)

Strings are parsed as paths or identifiers:

```jsonc
"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, ...]`

```jsonc
// 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:

| Key        | Purpose               | Example                   |
| ---------- | --------------------- | ------------------------- |
| `#literal` | Primitive values      | `{"#literal": 42}`        |
| `#struct`  | Named fields          | `{"#struct": {"x": ...}}` |
| `#list`    | Variable-size ordered | `{"#list": [...]}`        |
| `#tuple`   | Fixed-size ordered    | `{"#tuple": [...]}`       |
| `#dict`    | Key-value map         | `{"#dict": {"k": ...}}`   |
| `#type`    | Type annotation       | Used with other keys      |

### Literals

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

### Struct

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

### List and Tuple

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

### Dict

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

## Common Patterns

### Let Binding

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

### Function Definition

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

### Conditionals

```jsonc
["if", condition_expr, then_expr, else_expr]
```

### Comparison

```jsonc
["==", "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:**

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

**Filtering with comparison:**

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

**Struct with type:**

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

## References

- [Syntax Reference](references/syntax-reference.md) - Paths, function calls, operators
- [Special Forms](references/special-forms.md) - Language constructs (`if`, `let`, `fn`, `type`, `use`, etc.)
- [Data Constructors](references/data-constructors.md) - Typed data (`#literal`, `#struct`, `#tuple`, `#list`, `#dict`, `#type`)
- [Type DSL](references/type-dsl.md) - 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`

