Skip to main content

timon-scripting

Use when writing timon scripts to keep - named scripts in ~/.config/timon or a project's .timon, shared lib modules, settings in init.lua, structured concurrency with scope, and Fennel. Load the timon skill first for the basics.

Informations de source

Dépôt
joshrotenberg/timon
Dernière activité de la source
17 octobre 2026 à 03:26
Langue détectée de SKILL.md
anglais
Étoiles
0
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
timon-scripting
description
Use when writing timon scripts to keep - named scripts in ~/.config/timon or a project's .timon, shared lib modules, settings in init.lua, structured concurrency with scope, and Fennel. Load the timon skill first for the basics.
# Scripting with timon Run `timon` as a command of its own. A host that allows only `timon` commands denies the whole line when it has `;`, `&&`, `|`, `$?`, a redirect or a heredoc around timon. Pass multi-line Lua as one single-quoted argument, which may span lines and cannot contain `'`: use `"` for Lua strings, and put code whose text needs an apostrophe in a file run with `timon eval -f FILE`. Read files with `fs.read` in Lua instead of piping them in, and skip `$?`: a failure prints `timon: kind: message` and exits nonzero. ## Scripts A script is a `.lua` or `.fnl` file. Its arguments are in `arg` (`arg[1]`, ...) and `...`. ```lua fragment #!/usr/bin/env timon -- Print each argument doubled. local out = {} for i, a in ipairs(arg) do out[i] = tonumber(a) * 2 end return out ``` ```sh timon double.lua 1 2 3 # [2,4,6] ``` Flags, typed the way task options are: ```lua local opts, rest = cli.parse({ "--port", "9000", "-v", "notes.txt" }, { port = "integer?", verbose = { type = "boolean", short = "v" }, mode = { type = '"fast" | "full"', default = "fast", doc = "how hard to try" }, }) return opts.port, opts.verbose, opts.mode, rest[1] -- 9000, true, fast, notes.txt ``` In a script, `cli.parse(arg, options)`. An unknown flag or a bad value raises `usage` with did-you-mean, which exits 2; `cli.help(options)` is the text for a `--help`. Names use `_`, and the flag uses `-`: declare `max_depth`, pass `--max-depth` (or `--max_depth`). ## Named scripts and layers A named script is a task: `timon NAME` runs it. The same layout works for you and for a project: ``` ~/.config/timon/ (everywhere) <project>/.timon/ (one project) ├── init.lua settings ├── tasks.lua tasks with dependencies (the timon-tasks skill) ├── scripts/NAME.lua timon NAME [ARGS] ├── lib/NAME.lua require "NAME" ├── mcp/NAME.lua an MCP server: mcp.connect("NAME") └── skills/NAME/ SKILL.md, references/ ``` ```sh timon tasks # what is in reach, with the first line of each script's comment timon triage --all # runs scripts/triage.lua with "--all" in arg timon defs # layers, settings, scripts, lib directories ``` A project's `.timon/` loads only after a person reviews it and runs `timon trust`. Do not trust a project on someone's behalf. ## MCP servers MCP servers are timon's pods: programs whose tools a script calls. ```lua fragment -- .timon/mcp/crates.lua return { description = "crates.io", command = { "cratesio-mcp" } } ``` ```lua fragment local crates = mcp.connect("crates") -- or mcp.connect{ command = { "npx", "-y", "..." } } for _, t in ipairs(crates:tools()) do print(t.name, t.description) end local info = crates:call("get_crate_info", { name = "mlua" }) -- structured content, or text ``` A tool that reports an error raises `mcp_tool_failed`. The server stops when the scope that connected ends. From the shell: `timon mcp servers`, `timon mcp tools crates`, `timon mcp call crates get_crate_info name=mlua`. ## Script runs and resume A script that runs agents can describe itself. It returns `run` and its metadata instead of its result. `budget` applies to `run` like a scope budget: ```lua fragment -- .timon/scripts/review.lua -- Review each file named on the command line, then summarize. return { description = "Review files, then summarize", phases = { "review", "summary" }, budget = { runs = 10, usd = 1 }, run = function(...) phase("review") local reviews = par.map({ ... }, function(file) return agent.run{ prompt = "Review " .. file, label = file, output = "review" } end) phase("summary") return agent.ask("Summarize: " .. json.encode(reviews)) end, } ``` Every `timon NAME` and `timon FILE` is recorded, with its arguments, the sha256 of its source and its totals. Its agent runs point to it with `parent`: ```sh timon review src/a.rs src/b.rs timon runs --scripts # script runs: status, runs, cached, cost timon runs show s_1a2b # one script run: request, result, agent runs timon --resume s_1a2b review src/a.rs src/b.rs ``` `--resume` runs the script again. An agent run with the same request as one that succeeded in the earlier run returns that record with `cached = true`, and spends nothing. Read-only runs are reused. Runs with write access are reused only with `idempotent = true`, or in a worktree nothing has changed since. A cached record's text is the redacted text the record kept. ## Shared code in lib/ ```lua -- ~/.config/timon/lib/gh_util.lua local M = {} function M.ready(prs) return tbl.filter(prs, function(pr) return not pr.draft end) end return M ``` ```lua fragment -- any script local util = require("gh_util") ``` ## Settings `init.lua` returns a table of settings and can do no I/O. Project settings override user settings key by key. ```lua -- ~/.config/timon/init.lua return { defaults = { provider = "claude", model = "opus" }, limits = { concurrency = 4 }, } ``` ## Concurrency `scope(fn)` runs `fn(s)`; tasks spawned on `s` finish before it returns. If any task raises, the others are cancelled and the error is raised. ```lua local a, b = scope(function(s) local ha = s:spawn(function() sleep("20ms") return "slow" end) local hb = s:spawn(function() return "fast" end) return ha:await(), hb:await() end) return a, b -- slow, fast ``` Keep going past failures with `settle`: ```lua local results = par.map({ 1, 2, 3 }, function(n) if n == 2 then error({ kind = "bad_input", message = "two" }) end return n * 10 end, { settle = true }) return tbl.map(results, function(r) return r.ok and r.value or r.error.kind end) -- [10,"bad_input",30] ``` `par.race` returns the first result and cancels the rest: ```lua local value, i = par.race( function() sleep(10) return "slow" end, function() sleep("5ms") return "fast" end ) return value, i -- fast, 2 ``` ## Fennel Every module works from Fennel. Use `.fnl` files, `timon eval --fnl`, or `require` a `.fnl` module. ```fennel (local prs [{:number 12 :draft false} {:number 14 :draft true}]) (-> (tbl.filter prs (fn [pr] (not pr.draft))) (tbl.map (fn [pr] pr.number))) ``` ## Errors in scripts Raise structured errors so callers can branch on them: ```lua local function load_config(file) if not fs.exists(file) then error({ kind = "missing_config", message = file .. " does not exist", hint = "run setup first" }) end return json.decode(fs.read(file)) end local ok, err = try(load_config, "/no/config.json") return err.kind, err.hint -- missing_config, run setup first ```
Voir sur GitHub