Indicator authoring agent
The indicator builder's agent writes and edits one indicator script: inputs, outputs, dependencies, layers and onBar. Its edits apply straight to the code, and the chart beside the chat reloads with each one.
Ask it for values drawn on the chart. A setup marked in history is a definition, and numbers on a Forward Insight come from a study.
How an edit lands
Every edit saves. Code that does not compile is saved too: the chart keeps showing the last version that did, and the agent reads the error back from the same result and fixes it with another edit. Saving is not publishing: the indicator stays private until you change its visibility.
The only thing it asks you first is using another indicator from the library. That shows as an Indicator proposal card, such as Add VWAP?, with Approve and Reject.
Its loop on every change
Read the current script with
get_indicator_state.Decide the contract before writing: inputs, outputs, which pane each output lands on, the
ctx.accumslots, any timeframe handles.Save with
edit_indicator_code(a small exact replacement) orwrite_indicator_code(the whole file).Lint with
lint_indicatorand typecheck withtypecheck_indicator. Both read the saved script.Dry-run with
dry_run_indicator: the production engine over real bars from a preset market, dependencies included.For a script with
output.layer, grade the paint withbench_layer.Check the builder's chart with
wait_for_preview, theninspect_preview, and readctx.logoutput withget_indicator_logs.
A clean typecheck is not verification. It cannot tell a wrong number or a level in the wrong place; only the chart can.
Tools
Tool | Runs in | Does |
|---|---|---|
| Server | The saved script, manifest, defaults and latest version |
| Browser | Save a whole file or an exact replacement; returns compile, typecheck and bench results |
| Browser | Compiles the saved script in the chart's sandbox and lists every lint error and warning |
| Browser | Typechecks against the DSL's real declarations; reads those declarations |
| Server | Runs the saved script over a preset market. Returns outputs, |
| Server | Runs a layer's |
| Browser | Reads what the builder's chart calculated and logged |
| Server | Finds a dependency and its exact accessor keys and latest version |
| Browser, asks you | The Indicator proposal card |
| Server | Names the indicator on your first message, and renames it when its purpose changes |
What it checks before it calls a change done
Every
ctx.*call has a matchingoutput.*declaration of the right kind.output.priceLinepairs withctx.hline(id, price);output.hlinepairs withctx.hline(id, price, { time1 }). Mixing them draws nothing.Every output lands on the pane it was meant for: the dry run's
layout.empty_panesis empty.A marker's
pricegoes only with theatPrice*positions.mode: "invalidateOnCustomFunction"on a range or hline has aninvalidateWhen, and every hline emit under it passestime1.Every
ctx.params.<id>has an input, every input id is unique, and every dependency pins the version the search or approval returned.Cross-bar state lives in
ctx.accum,warmupis declared, and a signal that must wait for the close guards onctx.barConfirmed === false.A timeframe is a literal,
"chart"or aninput.timeframehandle, and nothing draws inside a timeframe handler.Time-zone conversions use
Intl.DateTimeFormat, never a fixed UTC offset.A layer's
bench_layerverdict ispassat all three bar spacings.
Asking well
Good requests name the output and the behaviour:
"Add a 20-period EMA overlay with a length input and a colour setting."
"Depend on ATR and draw close ± 1 ATR bands."
"Keep it an overlay; do not move it to a pane."
"The level on 12 March sits one bar late. Fix the anchor."
Requests it cannot do: emitting events (write a definition), putting study numbers on the chart (use Attach to chart), or importing npm packages (the sandbox has none).
