Your First Invkfile
Now that you've run your first command, let's build something more practical. We'll create an invkfile for a typical project with build, test, and deploy commands.
Understanding the Structure
An invkfile has a simple structure:
// invkfile.cue (commands only)
cmds: [ // Required: list of commands
// ... your commands here
]
Invkfiles define commands directly. If you want namespacing, use a module and set the module ID in invkmod.cue.
A Real-World Example
Let's create an invkfile for a Go project:
cmds: [
// Simple build command
{
name: "build"
description: "Build the project"
implementations: [
{
script: """
echo "Building..."
go build -o bin/app ./...
echo "Done! Binary at bin/app"
"""
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}
]
},
// Test command with subcommand-style naming
{
name: "test unit"
description: "Run unit tests"
implementations: [
{
script: "go test -v ./..."
runtimes: [{name: "native"}, {name: "virtual"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}
]
},
// Test with coverage
{
name: "test coverage"
description: "Run tests with coverage"
implementations: [
{
script: """
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
echo "Coverage report: coverage.html"
"""
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}
]
},
// Clean command
{
name: "clean"
description: "Remove build artifacts"
implementations: [
{
script: "rm -rf bin/ coverage.out coverage.html"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}]
}
]
}
]
Save this as invkfile.cue and try:
invowk cmd
You'll see:
Available Commands
(* = default runtime)
From current directory:
build - Build the project [native*]
test unit - Run unit tests [native*, virtual]
test coverage - Run tests with coverage [native*]
clean - Remove build artifacts [native*] (linux, macos)
Subcommand-Style Names
Notice how test unit and test coverage create a hierarchy. You run them like:
invowk cmd test unit
invowk cmd test coverage
This is just naming convention - spaces in the name create a subcommand feel. It's great for organizing related commands!
Multiple Runtimes
The test unit command allows both native and virtual runtimes:
runtimes: [{name: "native"}, {name: "virtual"}]
The first one is the default. You can override it:
# Use the default (native)
invowk cmd test unit
# Explicitly use virtual runtime
invowk cmd test unit --invk-runtime virtual
Platform-Specific Commands
The clean command only works on Linux and macOS (because it uses rm -rf):
platforms: [{name: "linux"}, {name: "macos"}]
If you try to run it on Windows, Invowk will show a helpful error message explaining the command isn't available on your platform.
Adding Dependencies
Let's make our build command smarter by checking if Go is installed:
{
name: "build"
description: "Build the project"
implementations: [
{
script: """
echo "Building..."
go build -o bin/app ./...
echo "Done!"
"""
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}
]
depends_on: {
tools: [
{alternatives: ["go"]}
]
filepaths: [
{alternatives: ["go.mod"], readable: true}
]
}
}
Now if you run invowk cmd build without Go installed, you'll get:
✗ Dependencies not satisfied
Command 'build' has unmet dependencies:
Missing Tools:
• go - not found in PATH
Install the missing tools and try again.
Environment Variables
You can set environment variables at different levels:
// Root-level env applies to ALL commands
env: {
vars: {
GO111MODULE: "on"
}
}
cmds: [
{
name: "build"
// Command-level env applies to this command
env: {
vars: {
CGO_ENABLED: "0"
}
}
implementations: [
{
script: "go build -o bin/app ./..."
// Implementation-level env is most specific
env: {
vars: {
GOOS: "linux"
GOARCH: "amd64"
}
}
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}
]
}
]
Environment variables merge with later levels overriding earlier ones.
What's Next?
You now know the basics of creating invkfiles! Continue learning about:
- Core Concepts - Deep dive into the invkfile format
- Runtime Modes - Learn about native, virtual, and container runtimes
- Dependencies - All the ways to declare dependencies