Write GitHub Actions workflows in any language. TypeScript, Python, Go, and
Rust ship as first-party languages, and custom languages plug in through the
plugin protocol. Loopt generates standard .github/workflows/*.yml from that
source, and can import existing workflow YAML into editable code.
Generated workflow files start with:
# Generated by loopt. Edit the source under .loopt/workflows and run loopt gen.
Edit .loopt/workflows/*, not the generated YAML.
Install
Prebuilt binaries, no Cargo required:
curl -fsSL https://raw.githubusercontent.com/preloopdev/loopt/main/install.sh | shThe script installs to ~/.local/bin and verifies the release checksum when
one is published. Set LOOPT_INSTALL_DIR to change the destination, or
LOOPT_VERSION=v0.1.1 to pin a release. Prebuilt binaries are published for
macOS arm64 and Linux x86_64.
The language you author in must be installed when generating: Node.js 26+, Python 3, Go, or Cargo/Rust.
Start a project
Writes a starter workflow as TypeScript source in .loopt/workflows/ci.ts,
generates .github/workflows/ci.yml from it, and prints what to do next. The
starter follows your project files:
| Found | Steps |
|---|---|
package.json |
npm ci (or npm install without a lockfile), npm test |
Cargo.toml |
cargo test |
go.mod |
go test ./... |
pyproject.toml, requirements.txt, setup.py |
pip install, python -m pytest |
| none of these | a placeholder step to replace |
Every starter uses a read-only token (contents: read), pins
actions/checkout to a commit without persisting credentials, cancels
superseded runs, and lints clean. Edit it freely; it is only a starting point.
loopt init --language python --name build --template node
--language is typescript (default), python, go, or rust. --name
sets the file name (default ci). --template is auto (default),
generic, node, rust, go, or python. init never overwrites an
existing workflow; use loopt import for those.
Use
# Import existing workflows into .loopt/workflows loopt import --language typescript # Generate .github/workflows from the source loopt gen # Fail if the committed YAML no longer matches the committed source loopt gen --check
loopt import leaves the original YAML untouched. loopt gen refuses to
overwrite a workflow edited outside Loopt unless you pass --force.
Composite actions (action.yml/action.yaml outside .github/workflows/)
import as action metadata the same way.
See Authoring workflows for composite-action
details, safe run templates, and the full source↔YAML sync semantics.
Review
Runs native correctness and security checks on generated workflows —
optionally with shellcheck on run: scripts.
loopt gen runs the same review automatically.
See Lint and security review for the
--persona/--context/--shellcheck flags and severity mapping.
Everything else
| Topic | Doc |
|---|---|
Typed, commit-pinned action imports (loopt actions …) |
Action bindings |
Names-only secret inventory (loopt secrets sync) |
Secrets |
uses: pin enforcement (loopt lock) |
Workflow lockfile |
| Out-of-tree plugin protocol and built-in languages | Languages and plugins |
@preloopdev/sdk (npm) and loopt-sdk (crates.io) |
Authoring SDKs |
| SDK call reference (all four languages) | SDK API |
| Releases, registry credentials, version bumps | Publishing |
.loopt/ layout |
Layout |
Test
The full external-fixture corpus test is opt-in:
PRELOOP_FIXTURES=/path/to/fixtures cargo test --test corpus -- --ignoredLicense
MIT.