Declarative substitute for shell scripts and the locally executable subset of pipelines
Predefined Rutinme Environment (PRE). A way to prepare and make progressive development, such as scaffolding or local deploy, using YAML and linking Bash commands in a blueprint. It is a simple CI/CD tool also (in its foundations) but starts before of that.
Basically, the way to operate consists in a YAML file where you define variables and steps with commands (bash sentences), then you are under your imagination (e.g. you can mix with scripts in javascript or python for more elaborated processes, like Service-Connections)
To use OnMind-PRE, first set a _pre.yml (or in another folder and name) with the following specification example (is similar to basic aspects of Azure Pipelines):
# Comment or Title
variables:
- name: name
value: there
- name: color
valueFrom: gum choose "Blue" "Green" "Pink" "Red" "White" "Yellow"
steps:
- bash: echo "Hi ${name}"
displayName: Hello
- bash: echo 'Your color is ${color}'In this way...
${name}and${color}are used to replace varariables by its values.valueFromallow reads bybashcommand usinggumas dependency (like in the example, but isn't Azure Pipelines compatible).- Variables also accept Azure Pipelines macro syntax
$(name)besides${name}. - Steps accept
continueOnError: true/falseper step (Azure-style), falling back to the--continue-on-errorglobal flag.
A step must define exactly one of
bash,checkout,copy,deleteorfetch
If valueFrom starts with the reserved word ask, the value is read with a native prompt (no external binary needed). Anything else (including gum ...) still runs as a shell command:
variables:
- name: color
valueFrom: ask select "Blue" "Green" "Pink"
- name: tags
valueFrom: ask multiselect "frontend" "backend" "docs"
- name: deploy
valueFrom: ask confirm "Deploy to production?"
- name: username
valueFrom: ask text "Your name"
- name: token
valueFrom: ask passwordSupported commands:
select(aliaschoose),multiselect(aliasmulti),confirm,text(aliasinput),password.
confirmstores"true"/"false";multiselectstores one selection per line (likegum choose --no-limit).
askrequires an interactive terminal.
Try it with the bundled example (uses ask select, no gum needed):
bun main.ts --config examples/pre_ask.ymlFor non-interactive runs (scripts, CI), feed variables from the command line instead of prompting:
bun main.ts --config deploy.yml --set env=prod --set tag=v2variables:
- name: env
valueFrom: arg # key defaults to the variable name (= --set env=...)
- name: tag
valueFrom: arg:tag # explicit key
default: latest # fallback when --set is absent
- name: token
valueFrom: env:API_TOKEN # from the environment (CI secrets friendly)Precedence:
--setwins over anything declared in the file.arg:without matching--set(and withoutdefault:) fails fast with a clear error; same for unsetenv:.
parameters: is the blueprint's input contract (homologated with Azure Pipelines runtime parameters — the ones behind the "Run pipeline" form). Distinction: valueFrom: arg is the read mechanism for one variable; parameters: declares what the blueprint accepts, with types, allowed values and required-ness — validated before anything runs:
parameters:
- name: env
values: [dev, prod] # allowed values (prompted as select when missing)
default: dev
- name: replicas
type: number # string (default) | number | boolean
default: 2
- name: token
type: string # no default = required
displayName: API token
variables:
- name: app
value: demoSupplied values are type-checked and canonicalized (
03→3,yes→true); all problems are reported at once, fail-fast. A missing required parameter is prompted in interactive terminals (select forvalues:, confirm forboolean, text otherwise — the terminal "Run pipeline" form) and errors out in CI. Resolved parameters seed the run, sovariables:/steps:use them like any other variable; a variable duplicating a parameter name is an error. Unknown--setkeys warn without stopping.
Variables can also be sourced from files (same default: fallback rules as above):
variables:
- name: token
valueFrom: dotenv:.env:API_TOKEN # KEY from a dotenv file (comments, quotes, `export` supported)
- name: version
valueFrom: file:VERSION # whole file content, trimmedThe path can reference variables resolved earlier (e.g.
dotenv:${envDir}/.env:KEY). Missing file or KEY fails fast unlessdefault:is set.
A step can clone a repository instead of running a bash command (homologated with Azure Pipelines steps.checkout:
steps:
- checkout: https://github.com/${repo}.git
path: ../output
displayName: Clone / Checkout
- checkout: none
displayName: No sources
pathdefaults to./<repo-name>derived from the URL. If the path already exists the clone is skipped, unlessclean: true(removes it and clones fresh).branch: <name>selects the branch (PRE extension).fetchDepth: 1downloads only the current version (shallow clone;0/unset = full history). Variables accept both${var}and$(var), anddisplayName,continueOnErrorandparallelwork as withbashsteps.
A step can declare when it runs (homologated with Azure Pipelines condition):
steps:
- bash: "echo 'deploying to ${env}'"
condition: eq('${env}', 'prod')
- bash: "echo 'cleanup'"
condition: always()Supported:
always(),succeeded(),failed(),succeededOrFailed(),not(),and(),or(),eq(),ne(),contains(),startsWith(),endsWith(). Variable refs can use'$(var)','${var}'(quoted) or barevariables['var']/variables.var; unknown variables expand to empty string. The default condition issucceeded(): after a failure onlyfailed()/always()/succeededOrFailed()steps still run, and the run exits 1 at the end (unlesscontinueOnError).
Try failure handling + template rendering with the bundled example (exits 1 by design):
bun main.ts --config examples/pre_blue.ymlSteps can copy or delete files instead of running bash (homologated with Azure CopyFiles@2 / DeleteFiles@1:
steps:
- copy: ./templates
target: ./output
contents:
- "**/*.yml"
- "!**/node_modules/**"
clean: true
displayName: Copy templates
- delete: ./output/**/*.tmp
displayName: Clean temp files
targetis always a directory (created if missing).contentsdefaults to all files (dotfilesincluded);!negates a pattern.clean: trueremoves the target first;overwrite: falsekeeps existing files.deleteaccepts a literal path/dir or a glob relative to the working directory. Variables accept both${var}and$(var), anddisplayName,condition,continueOnErrorandparallelwork as withbashsteps.
Steps can render a file with the run variables (PRE-native scaffolding core):
steps:
- template: ./examples/tpl/app.txt.tpl
target: ./output/
displayName: Render template
targetis the output file (created with parents if missing). Iftargetis a directory (or ends with/), the file name comes from the source with a trailing.tplstripped (app.txt.tpl→app.txt). Both${var}and$(var)in the content are substituted.
No curl/jq needed (native fetch, PRE-native — neither Azure nor GHA has a generic HTTP step). Variables can be fetched from an API, and steps can download files or call APIs:
variables:
- name: tag
valueFrom: https://api.github.com/repos/myorg/myrepo/releases/latest | .tag_name
headers:
Authorization: Bearer ${GITHUB_TOKEN}steps:
- fetch: https://example.com/pkg.tgz
path: ./downloads/pkg.tgz
displayName: Download package
- fetch: https://api.example.com/deploy
method: POST
headers:
Authorization: Bearer ${TOKEN}
body: '{"tag":"${tag}"}'
path: ./logs/deploy.json
valueFrom: "<url>"returns the trimmed body, or the value at"<url> | <selector>"(.a.b[0].csyntax) parsed as JSON.fetch:saves raw bytes (pathdefaults to./<basename-of-url>). Non-2xx responses fail fast unlessdefault:(variables) /continueOnError(steps) is set.timeout:(seconds, default 30) applies to both. Secrets stay out of the file by sourcing header values fromenv:/arg:params.
Try it with the bundled example (needs internet):
bun main.ts --config examples/pre_url.ymlTo run OnMind-PRE from binaries just check release in this repo and download the file for your system. Then, launch the app like this:
./onmind-pre-mac --config examples/pre_app.yml
onmind-pre-macis the version for macOS, but it could beonmind-pre-winfor Windows, even a version for Linux
--configis used to specify another path and file name for YAML
Alternatively, to run OnMind-PRE from sources, after clonning, launch the app like this:
bun install
bun main.ts --config examples/pre_app.ymlYou can add the
--configargument with the path andymlfile with configuration.
To usegumwithvalueFrominvariables, install it first, e.g.:go install github.com/charmbracelet/gum@latest
To compile OnMind-PRE into self-contained binaries (requires Bun):
bun build --compile ./main.ts --outfile onmind-pre-mac
bun build --compile --target=bun-linux-x64 ./main.ts --outfile onmind-pre-linux
bun build --compile --target=bun-windows-x64 ./main.ts --outfile onmind-pre-win.exeYAMLException: bad indentation of a mapping entry— abash:(orcheckout:/path:) value contains:unquoted, which YAML reads as a nested mapping. Quote the whole value:# Fails (`: ` inside the value) - bash: echo 'done: ${name}' # Works - bash: "echo 'done: ${name}'"
- Raw stack dump on startup (
YAMLException ... Bun v...) — the YAML file itself is invalid. There is no friendly error yet: validate indentation, quotes and list dashes (-) in your_pre.yml.