hello-tool
The smallest possible OpenExpertise experience: one tool node writes a greeting to state.
What it demonstrates
- A single
toolnode as the complete graph - The
state.schemacontract:namein,greetingout - How a tool returns
state_deltato the runtime - Baseline event log structure (run.started → state.write → run.finished)
The graph
graph:
nodes:
- id: greet
kind: tool
impl: ./tools/greet.mjs
args:
name: World
writes: [greeting]
edges: []No edges — a single node is a valid DAG.
State schema
| Field | Type | Direction | Description |
|---|---|---|---|
name | string | in (via --args) | Subject of the greeting |
greeting | string | out | Produced by greet.mjs |
How it runs
oe validate examples/hello-tool
oe run examples/hello-tool --args '{}'No ANTHROPIC_API_KEY required. No external CLIs required.
To greet someone specific:
oe run examples/hello-tool --args '{"name":"Alice"}'What happens
- The scheduler starts a run, emits
run.started. greetis dispatched toToolDispatcher, which callsgreet.mjs.greet.mjsreturns{ state_delta: { greeting: "hello, World" } }.- The runtime writes
greetingto the SQLite blackboard, emitsstate.write. - Run finishes, emits
run.finished.
$ oe state greeting
hello, WorldThe event log at .openexpertise/runs/<run-id>.jsonl has exactly three events — easy to read through when you're learning how OpenExpertise works.
How greet.mjs is implemented
export default async function greet(args) {
return { state_delta: { greeting: `hello, ${args.name}` } }
}The function receives the node's args bundle and must return an object with a state_delta key. Fields in state_delta are merged into state.
Try it: variations
1. Change the greeting message. Edit greet.mjs to return HELLO, ${args.name.toUpperCase()}!. Re-run — no schema changes needed.
2. Add a second tool node. Add a farewell node that reads greeting and writes goodbye. Add an edge { from: greet, to: farewell }. This shows sequential tool chaining without any LLM.
3. Pass a dynamic name at run time. Change args.name to "" in the YAML. Then run with --args '{"name":"Bob"}'. (Note: you'll need a seed tool node to write name into state first, since V1 --args are not auto-propagated into node bundles — see the cli-orchestration walkthrough for the pattern.)
Start here
hello-tool is the best first example to read if you want to understand how nodes, state, and the event log fit together before touching an LLM.