samamco/track-and-graph/write-track-and-graph-function

Claude Code and agent skill by samamco/track-and-graph

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Write or revise a pasteable custom Lua function for the Track & Graph Android app. Use for data-stream transformations in the Function node editor; do not use for Lua graph scripts or community-catalog contributions.

Install

npx vskill@latest install samamco/track-and-graph/write-track-and-graph-function

SKILL.md

Write a Track & Graph custom function

Create a single-file Lua function that the user can paste into a Custom Lua Script node in Track & Graph. Optimize for an individual editing and using their own script, not for publication in the community catalog.

Establish the behavior

Before writing code, determine the following from the request or make the simplest reasonable assumptions:

  • What each input stream represents and how many inputs are needed.
  • Which settings should be editable in the node UI.
  • Which fields must be preserved or changed: timestamp, value, label,

note, and offset.

  • For time-based behavior, whether the user means a fixed amount of elapsed

time (such as exactly 24 hours) or a calendar-relative amount (such as the previous local day, which can be 23 or 25 hours across daylight-saving changes).

  • Which point should supply the timestamp when several points contribute to an

output.

Ask a concise question only when different answers would materially change the result. State important assumptions in the response.

Target the user's app version

Ask the user which version of Track & Graph they use; it is shown in the app's About screen. APIs can differ between releases, so do not assume that the current master branch describes their installed version.

Use the matching release tag from the Track & Graph tags, normally named v<app-version> or rc-v<app-version>. Inspect the lua/src/tng/ module source and its matching .apispec.lua file at that tag before using an API. For example, replace <TAG> and <MODULE> in:

text
https://raw.githubusercontent.com/SamAmco/track-and-graph/refs/tags/<TAG>/lua/src/tng/<MODULE>.lua
https://raw.githubusercontent.com/SamAmco/track-and-graph/refs/tags/<TAG>/lua/src/tng/<MODULE>.apispec.lua

Each API spec maps an exported symbol to the API level in which it was introduced. An app release supports the symbols present in its tagged module source; the highest integer across its bundled API specs is that release's maximum API level. A function's version major declares the highest API level it requires for catalog compatibility, but adding version does not make an unavailable API work in an older app.

If the user cannot identify their version, prefer long-established APIs and say that the script targets the current release. Do not use a newer API merely because it appears on master when the requested app version predates it.

Use the custom-script shape

The absolute minimum is a script that returns a generator function:

lua
return function(source)
return function()
local data_point = source.dp()
if not data_point then
return nil
end
data_point.value = math.abs(data_point.value)
return data_point
end
end

The outer function is called once to create an iterator. The iterator is then called repeatedly. Each call must return one data-point table or nil when the output is exhausted.

For a useful title, description, multiple inputs, or settings, return a metadata table instead:

lua
local number = require("tng.config").number
return {
title = "Multiply values",
description = [[Multiplies each value while preserving the other fields.]],
inputCount = 1,
config = {
number {
id = "multiplier",
name = "Multiplier",
default = 1,
},
},
generator = function(source, config)
local multiplier = config.multiplier
return function()
local data_point = source.dp()
if not data_point then
return nil
end
data_point.value = data_point.value * multiplier
return data_point
end
end,
}

Use plain strings in the user's language for title, description, config names, and enum option names. A custom function does not need translations, shared translation keys, categories, an ID, or catalog tests.

Default to an editable script

Omit version by default. In Track & Graph, any non-nil version marks the node as catalog-style and hides its clipboard, file, and script-editing controls. Omitting it keeps the script easy for the user to inspect and repair inside the app.

Some users may prefer a configuration-only node with its implementation hidden. Explain the tradeoff and offer version as an explicit option when appropriate, ideally after the script is working. Do not add it silently. If the user opts in, set its semantic-version major to the highest API level the script uses and warn that later code changes will require recreating or otherwise replacing the node from an editable copy.

Do not copy _-prefixed shared translation keys from community functions. Those keys are hydrated by catalog context and otherwise appear to the user as raw strings such as _period.

Runtime contract

Data sources are lazy and are traversed in reverse chronological order: newest point first.

For one input (the default), the generator receives that data source directly:

lua
generator = function(source, config)

For two or more inputs, set inputCount and receive a one-indexed table:

lua
return {
inputCount = 2,
generator = function(sources, config)
local left = sources[1]
local right = sources[2]
-- Return an iterator here.
end,
}

Do not pair multiple streams merely by calling dp() once on each unless position-based pairing is truly intended. Independently recorded streams often have different timestamps; define the desired timestamp matching, tolerance, or pass-through behavior.

source.dp() consumes the next point and is the fundamental streaming operation. Before using batch, cutoff, or other data-source operations, inspect the DataSource section of the version-appropriate tng.core source and API spec. Do not reproduce an API from memory: its availability or contract may differ in the user's version.

Prefer streaming only the data points you need to calculate the next output data point. Keep per-run state inside the generator, not at script/module scope.

Filtering iterators must keep consuming until they find a point to return or reach the end:

lua
return function()
while true do
local data_point = source.dp()
if not data_point then
return nil
end
if data_point.value >= threshold then
return data_point
end
end
end

If an algorithm is naturally chronological (oldest to newest), account for the input order explicitly. It may need to buffer the full input using an operation available in the user's version, calculate from the end of that array toward the beginning, and still emit results newest first.

Data points and time

An input data point contains:

FieldTypeMeaning
timestampnumberUnix epoch milliseconds; required on output
offsetnumberUTC offset in seconds
valuenumberTracked numeric value
labelstringLabel, normally an empty string when absent
notestringNote, normally an empty string when absent

Mutate and return the input table when only changing a field; this naturally preserves the other fields. When constructing a new point, supply a valid timestamp, and preserve or deliberately choose offset, label, and note.

For local calendar calculations, use the full point:

lua
local core = require("tng.core")
local date = core.date(data_point)

Passing only data_point.timestamp loses the point's offset and interprets the instant in UTC. In the Track & Graph API, core.DURATION represents an exact number of elapsed milliseconds, like Java Time's Duration. core.PERIOD represents calendar-relative days, weeks, months, or years, like Java Time's Period; shifting by one local day can therefore span 23, 24, or 25 elapsed hours. Use the version-appropriate tng.core documentation to confirm the available constants and functions.

If output values represent elapsed time, remind the user to enable Duration on the function's Output node; that setting is outside the Lua script.

Configuration

Inspect the version-appropriate tng.config source and API spec before choosing a configuration type. Do not assume that every type on master exists in the user's installed release. A typical numeric configuration looks like:

lua
local number = require("tng.config").number
number {
id = "threshold",
name = "Threshold",
default = 0,
}

Confirm units in that tagged API source. For example, releases that provide duration, local-time, and instant inputs pass them to the generator as duration milliseconds, milliseconds since midnight, and epoch milliseconds respectively—but the tagged source remains authoritative.

For a custom enum, always provide stable IDs and plain display names:

lua
enum {
id = "operation",
name = "Operation",
options = {
{ id = "add", name = "Add" },
{ id = "subtract", name = "Subtract" },
},
default = "add",
}

Do not use a bare string array for enum options; that form is intended for catalog translation keys.

Declare defaults in the config specification. If defensive fallback logic is also needed, do not accidentally replace a valid false value:

lua
local enabled = true
if config and config.enabled ~= nil then
enabled = config.enabled
end

config and config.enabled or true is wrong here because explicit false would become true: in Lua, false or true evaluates to true. The explicit nil check above does preserve false, because false ~= nil is true and the assignment therefore sets enabled to false.

Available APIs and environment

The app embeds a Lua 5.2-compatible LuaK/LuaJ environment. Scripts are single files and cannot access the network, operating system, or filesystem. They may load only the modules supplied by Track & Graph.

Use the release-tag lookup described above as the primary API reference. These master links describe current development and are only the fallback when the user is on the current release or their version is unknown:

Do not use tng.graph; graph scripts have a different contract and output shape.

Validate the result

Before delivering the script, reason through at least:

  • An empty source.
  • A single data point.
  • Typical input with exact expected outputs.
  • Boundary values and missing/empty labels or notes when relevant.
  • Default and non-default configuration, including explicit false.
  • Reverse-chronological ordering and the timestamp/offset of generated points.
  • Exhaustion or mismatch behavior for every input in a multi-input function.

Check that every iterator path either returns a data point, continues consuming input, or terminates with nil; avoid loops that can make no progress. Preserve fields the user did not ask to change. Do not claim the script was tested in Track & Graph unless it actually was.

Deliver the function

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
655
Repository forks
61
7-day trend score
0

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/samamco/track-and-graph/write-track-and-graph-function/badge)](https://verified-skill.com/skills/samamco/track-and-graph/write-track-and-graph-function)

Something wrong with this skill or its page? Tell us.