npm package: @hnsvn/tokay
Description: Workflow runtime for AI agents - deterministic pipelines with approval gates
Latest version: 2026.4.6

# Tokay

An HnsAi-native workflow shell: typed (JSON-first) pipelines, jobs, and approval gates.


## Example of Tokay at work
HnsAi (or any other AI agent) can use `tokay` as a workflow engine and avoid re-planning every step — saving tokens while improving determinism and resumability.

### Watching a PR that hasn't had changes
```
node bin/tokay.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"hnsvn/hnsai\",\"pr\":1152}'"
[
  {
    "kind": "github.pr.monitor",
    "repo": "hnsvn/hnsai",
    "prNumber": 1152,
    "key": "github.pr:hnsvn/hnsai#1152",
    "changed": false,
    "summary": {
      "changedFields": [],
      "changes": {}
    },
    "prSnapshot": {
      "author": {
        "id": "MDQ6VXNlcjE0MzY4NTM=",
        "is_bot": false,
        "login": "vignesh07",
        "name": "Vignesh"
      },
      "baseRefName": "main",
      "headRefName": "feat/tokay-plugin",
      "isDraft": false,
      "mergeable": "MERGEABLE",
      "number": 1152,
      "reviewDecision": "",
      "state": "OPEN",
      "title": "feat: Add optional tokay plugin tool (typed workflows, approvals/resume)",
      "updatedAt": "2026-01-18T20:16:56Z",
      "url": "https://github.com/hnsvn/hnsai/pull/1152"
    }
  }
]
```
### And a PR that has a state change (in this case an approved PR)

```
 node bin/tokay.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"hnsvn/hnsai\",\"pr\":1200}'"
[
  {
    "kind": "github.pr.monitor",
    "repo": "hnsvn/hnsai",
    "prNumber": 1200,
    "key": "github.pr:hnsvn/hnsai#1200",
    "changed": true,
    "summary": {
      "changedFields": [
        "number",
        "title",
        "url",
        "state",
        "isDraft",
        "mergeable",
        "reviewDecision",
        "updatedAt",
        "baseRefName",
        "headRefName"
      ],
      "changes": {
        "number": {
          "from": null,
          "to": 1200
        },
        "title": {
          "from": null,
          "to": "feat(tui): add syntax highlighting for code blocks"
        },
        "url": {
          "from": null,
          "to": "https://github.com/hnsvn/hnsai/pull/1200"
        },
        "state": {
          "from": null,
          "to": "MERGED"
        },
        "isDraft": {
          "from": null,
          "to": false
        },
        "mergeable": {
          "from": null,
          "to": "UNKNOWN"
        },
        "reviewDecision": {
          "from": null,
          "to": ""
        },
        "updatedAt": {
          "from": null,
          "to": "2026-01-19T05:06:09Z"
        },
        "baseRefName": {
          "from": null,
          "to": "main"
        },
        "headRefName": {
          "from": null,
          "to": "feat/tui-syntax-highlighting"
        }
      }
    },
    "prSnapshot": {
      "author": {
        "id": "MDQ6VXNlcjE0MzY4NTM=",
        "is_bot": false,
        "login": "vignesh07",
        "name": "Vignesh"
      },
      "baseRefName": "main",
      "headRefName": "feat/tui-syntax-highlighting",
      "isDraft": false,
      "mergeable": "UNKNOWN",
      "number": 1200,
      "reviewDecision": "",
      "state": "MERGED",
      "title": "feat(tui): add syntax highlighting for code blocks",
      "updatedAt": "2026-01-19T05:06:09Z",
      "url": "https://github.com/hnsvn/hnsai/pull/1200"
    }
  }
]
```

## Goals


- Typed pipelines (objects/arrays), not text pipes.
- Local-first execution.
- No new auth surface: Tokay must not own OAuth/tokens.
- Composable macros that HnsAi (or any agent) can invoke in one step to save tokens.

## Quick start

From this folder:

- `pnpm install`
- `pnpm test`
- `pnpm lint`
- `node ./bin/tokay.js --help`
- `node ./bin/tokay.js doctor`
- `node ./bin/tokay.js "exec --json --shell 'echo [1,2,3]' | where '0>=0' | json"`

### Notes

- `pnpm test` runs `tsc` and then executes tests against `dist/`.
- `bin/tokay.js` prefers the compiled entrypoint in `dist/` when present.
## Commands

- `exec`: run OS commands
- `exec --stdin raw|json|jsonl`: feed pipeline input into subprocess stdin
- `where`, `pick`, `head`: data shaping
- `json`, `table`: renderers
- `approve`: approval gate (TTY prompt or `--emit` for HnsAi integration)

## Next steps

- HnsAi integration: ship as an optional HnsAi plugin tool.

## Workflow files

Tokay workflow files are meant to read like small scripts:

- `run:` or `command:` for deterministic shell/CLI steps
- `pipeline:` for native Tokay stages like `llm.invoke`
- `approval:` for hard workflow gates between steps
- `stdin: $step.stdout` or `stdin: $step.json` to pass data forward

```
tokay run path/to/workflow.tokay
tokay run --file path/to/workflow.tokay --args-json '{"tag":"family"}'
```

Example file:

```yaml
name: jacket-advice
args:
  location:
    default: Phoenix
steps:
  - id: fetch
    run: weather --json ${location}

  - id: confirm
    approval: Want jacket advice from the LLM?
    stdin: $fetch.json

  - id: advice
    pipeline: >
      llm.invoke --prompt "Given this weather data, should I wear a jacket?
      Be concise and return JSON."
    stdin: $fetch.json
    when: $confirm.approved
```

Notes:

- `run:` and `command:` are equivalent; `run:` is the preferred spelling for new files.
- `pipeline:` shares the same args/env/results model as shell steps, so later steps can still reference `$step.stdout` or `$step.json`.
- If you need a human checkpoint before an LLM call, use a dedicated `approval:` step in the workflow file rather than `approve` inside the nested pipeline.
- `cwd`, `env`, `stdin`, `when`, and `condition` work for both shell and pipeline steps.

## Calling LLMs from workflows

Use `llm.invoke` from a native `pipeline:` step for model-backed work:

```bash
llm.invoke --prompt 'Summarize this diff'
llm.invoke --provider hnsai --prompt 'Summarize this diff'
llm.invoke --provider pi --prompt 'Summarize this diff'
```

Provider resolution order:

- `--provider`
- `TOKAY_LLM_PROVIDER`
- auto-detect from environment

Built-in providers today:

- `hnsai` via `HNSAI_URL` / `HNSAI_TOKEN`
- `pi` via `TOKAY_PI_LLM_ADAPTER_URL` (typically supplied by the Pi extension)
- `http` via `TOKAY_LLM_ADAPTER_URL`

`llm_task.invoke` remains available as a backward-compatible alias for the HnsAi provider.

## Calling HnsAi tools from workflows

Shell `run:` steps execute in your system shell, so HnsAi tool calls there must be real executables.

If you install Tokay via npm/pnpm, it installs a small shim executable named:

- `hnsai.invoke` (preferred)
- `huyd.invoke` (alias)

These shims forward to the Tokay pipeline command of the same name.

### Example: invoke llm-task

Prereqs:

- `HNSAI_URL` points at a running HnsAi gateway
- optionally `HNSAI_TOKEN` if auth is enabled

```bash
export HNSAI_URL=http://127.0.0.1:18789
# export HNSAI_TOKEN=...
```

In a workflow:

```yaml
name: hello-world
steps:
  - id: greeting
    run: >
      hnsai.invoke --tool llm-task --action json --args-json '{"prompt":"Hello"}'
```

### Passing data between steps (no temp files)

Use `stdin: $stepId.stdout` to pipe output from one step into the next.

## Args and shell-safety

`${arg}` substitution is a raw string replace into the shell command text.

For anything that may contain quotes, `$`, backticks, or newlines, prefer env vars:

- every resolved workflow arg is exposed as `TOKAY_ARG_<NAME>` (uppercased, non-alnum → `_`)
- the full args object is also available as `TOKAY_ARGS_JSON`

Example:

```yaml
args:
  text:
    default: ""
steps:
  - id: safe
    env:
      TEXT: "$TOKAY_ARG_TEXT"
    command: |
      jq -n --arg text "$TEXT" '{"result": $text}'
```