harn-skills 0.10.78

Embedded skill corpus for the Harn CLI and runtime
Documentation
---
name: harn-language
short: Harn syntax, modules, types, diagnostics, and script structure.
description: Use for Harn language syntax, typechecking, modules, imports, and idiomatic script authoring.
when_to_use: Use when writing, reviewing, or explaining Harn source code and language-level behavior.
---

# Harn language

Use this skill when writing, reviewing, or explaining `.harn` source code.

Pair it with [[harn-testing]] for fixtures and [[harn-diagnostics]] for user-facing errors.

## Start here

- Read `docs/llm/harn-quickref.md` before editing `.harn` files.
- In a Harn worktree, run `make setup` once and use
  `HARN_BIN_NO_BUILD=1 ./scripts/harn_bin.sh -- <command>` for narrow CLI
  checks. This resolves the lane-local binary without starting a hidden Cargo
  build. Outside the repository, use the installed, pinned `harn` executable.
- Use `docs/llm/harn-triggers-quickref.md` when trigger manifests are involved.
- Read `spec/HARN_SPEC.md` as the assembled language reference.
- Default new script entrypoints to `fn main(harness: Harness) { ... }` and
  route side effects through `harness.*`.
- Use `harness.fs.mkdtemp_in_workspace(prefix?)` for scratch files that must be
  visible under sandbox policy; avoid composing `.harn/tmp` paths by hand.
- Use typed `std/fs` conditional replacement for shared state or artifacts
  that must not overwrite a newer observation; branch on the closed receipt.
- Use bounded `std/jsonl` pages for file-backed logs and transcripts. Apply a
  `SchemaContract<T>` when consumers need typed records and named rules.
- For connector credentials, read canonical ids such as
  `provider/access-token` through `harness.secrets` from a package script; the
  runner scopes the default provider from the nearest `harn.toml`.
- Edit the authoritative chapters under `spec/chapters/*.md` for spec changes;
  never hand-edit the generated `spec/HARN_SPEC.md` or
  `docs/src/language-spec.md` projections.
- Regenerate and verify every spec projection with `make sync-language-spec`.
- Check user-visible behavior with conformance fixtures under `conformance/tests/`.
- Keep examples small enough for agents to copy without hidden setup.
- Prefer existing syntax and stdlib helpers over new host-side shortcuts.
- Put platform spellings, policy rows, and other closed configuration in one
  typed data-only module. Import that value into the evaluator and mechanically
  project it downstream instead of duplicating lists or host branches.

## Syntax checklist

- Imports go first.
- `pipeline` is the usual entry-point construct.
- `fn` is for reusable pure or host-backed logic.
- `let` binds values; avoid mutation unless the language surface requires it.
- Use explicit type annotations at boundaries.
- Use `match` for variant-sensitive behavior.
- Use `for` for straightforward iteration.
- Use `parallel each` for bounded fan-out work.
- Use `parallel settle` when collecting settled outcomes matters.
- Use `settle_with_abort` from `std/abort` when outcomes matter *and*
  branches poll or wait, so one branch's doomed verdict can stop the rest.
- Always set `max_concurrent` on broad parallel work.
- Use triple-quoted strings for long prompts in Harn source.
- Heredoc syntax is for LLM tool-call argument JSON, not general strings.
- Keep comments factual and close to non-obvious logic.

## Types and boundaries

- Treat `unknown` as the type for untrusted inputs.
- Use `SchemaContract<T>` for deterministic cross-field rules after structural
  validation. Capture typed context in the rule closure; do not replace it with
  an open dictionary.
- Use `ArtifactDescriptor<T>` when a producer and consumer share a durable JSON
  artifact. Bind its relative name and `SchemaContract<T>` once, then reuse the
  descriptor for reads and writes.
- Narrow `unknown` with `type_of`, `schema_is`, or validated helpers.
- Use `any` only as an explicit escape hatch.
- Do not erase types merely to silence the typechecker.
- Keep struct and enum names stable when they are user-facing.
- Add conformance coverage before changing type inference behavior.
- Preserve diagnostic codes and spans when refactoring typechecker logic.
- Keep imported callable declarations aligned with module graph behavior.
- Watch for strict-types behavior when changing boundary APIs.
- Update examples when public type syntax changes.

## Portable execution

- Treat portable execution as a deployment contract, not a second Harn
  language. Source must use the canonical parser, typechecker, and compiler.
- Passing `harn check` is necessary but does not prove Portable Kernel v1
  support. Compile the intended entry through the portable interface so
  unsupported opcodes, builtins, and capability methods fail explicitly.
- Keep entry inputs and terminal values JSON-shaped: null, booleans, signed
  integers, finite or tagged floats, strings, bytes, lists, and named records.
- Preserve explicit type annotations at the entry and reusable function
  boundaries. The portable kernel enforces declared call contracts rather than
  treating browser JSON as `any`.
- Route privileged operations through typed `harness` capabilities. Do not add
  target-specific browser builtins or read ambient file, network, process,
  clock, random, or model authority.
- Keep DOM, canvas, and presentation state in the browser host. Run CPU-heavy
  portable behavior in a Web Worker and exchange typed values.
- Do not add a parser, evaluator, opcode table, builtin registry, or keyword
  list to an adapter. Generate projections or test parity against the owning
  language/runtime registry.
- Use `harn bench portable` for compiler, artifact decode, and dispatch
  measurements. Use `std/timing` only for hostful application spans.

## Modules and imports

- Keep import paths explicit and readable.
- Prefer `import * as alias from "module"` when a module publishes short
  member names under a collision-safe alias; do not invent receiver-method
  APIs for that case.
- When callers use a namespace alias, export `event` rather than repeating the
  module name in `ui_event`; the call site already reads `ui.event`.
- `pub import * as alias from "module"` re-exports the alias namespace object,
  not the target's flattened members (contrast `pub import "module"`).
- Avoid relying on the current working directory in examples.
- When touching module resolution, inspect `crates/harn-modules`.
- Cross-file checks should use the same module graph as the CLI.
- Public symbols should remain discoverable by editor tooling.
- Use curated `pub import` facades for stable package surfaces; package checks
  and API docs follow re-exports to the original declaration.
- Avoid duplicate import spellings for the same file.
- Prefer canonical relative paths in fixtures.
- Add a cycle regression when changing import traversal.
- Keep generated docs and tree-sitter grammar in sync after syntax changes.
- Use [[harn-orchestration]] when module behavior affects workflows.

## Prompt templates

- The template engine lives in `crates/harn-vm/src/stdlib/template.rs`.
- Do not add a second prompt-template parser.
- Keep host-call and script-call rendering behavior identical.
- Preserve pre-v2 `{{name}}` missing-identifier passthrough.
- New template constructs should fail with useful parse diagnostics.
- Update `docs/src/prompt-templating.md` for template syntax changes.
- Update `docs/llm/harn-quickref.md` when agents need the new syntax.
- Update VS Code grammar when `.harn.prompt` syntax changes.
- Add conformance fixtures under `conformance/tests/template_*`.
- Use [[harn-diagnostics]] for template parse and lint diagnostics.

## Simpler first

- Can this be ordinary Harn instead of Rust?
- Can a stdlib helper express this without a new language form?
- Can the typechecker infer it without a new annotation?
- Can a conformance fixture capture the behavior without a large harness?
- Can docs describe the rule in one sentence?
- Can the formatter preserve the style without special cases?
- Can the linter derive the rule from existing AST structure?
- Can the tree-sitter grammar remain a direct mirror of parser syntax?
- Can existing examples be updated mechanically?
- Can user-visible behavior stay backward compatible?

## Verify

- Narrow script check:
  `HARN_BIN_NO_BUILD=1 ./scripts/harn_bin.sh -- check <path>`.
- Narrow lint check:
  `HARN_BIN_NO_BUILD=1 ./scripts/harn_bin.sh -- lint <path>`.
- Narrow format check:
  `HARN_BIN_NO_BUILD=1 ./scripts/harn_bin.sh -- fmt --check <path>` (`fmt`,
  never `format`).
- Narrow conformance case:
  `HARN_BIN_NO_BUILD=1 ./scripts/harn_bin.sh -- test conformance --filter <name>`.
- Parser changes: `make test ARGS='-p harn-parser <filter>'`.
- Formatter changes: `make test ARGS='-p harn-fmt <filter>'`.
- Linter changes: `make test ARGS='-p harn-lint <filter>'`.
- Syntax or keyword changes: `make conformance`.
- Harn fixture changes: `make lint-harn` and `make fmt-harn`.
- Tree-sitter changes: `(cd tree-sitter-harn && npm test)`.