Working Directory
Control where your commands execute with the workdir setting. This is especially useful for monorepos and projects with complex directory structures.
Default Behavior
By default, commands run in the current directory (where you invoked invowk).
Setting Working Directory
Command Level
{
name: "build frontend"
workdir: "./frontend" // Run in frontend subdirectory
implementations: [{
script: "npm run build"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}]
}
Implementation Level
{
name: "build"
implementations: [
{
script: "npm run build"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
workdir: "./web" // This implementation runs in ./web
},
{
script: "go build ./..."
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
workdir: "./api" // This implementation runs in ./api
}
]
}
Root Level
workdir: "./src" // All commands default to ./src
cmds: [
{
name: "build"
// Inherits workdir: ./src
implementations: [...]
},
{
name: "test"
workdir: "./tests" // Override to ./tests
implementations: [...]
}
]
CLI Override
Override the working directory at runtime:
invowk cmd build --ivk-workdir ./frontend
Path Types
Relative Paths
Relative to the invowkfile location:
workdir: "./frontend"
workdir: "../shared"
workdir: "src/app"
Absolute Paths
Full system paths:
workdir: "/opt/myapp"
workdir: "/home/user/projects/myapp"
Environment Variables
Expand variables in paths:
workdir: "${HOME}/projects/myapp"
workdir: "${PROJECT_ROOT}/src"
Precedence
Implementation overrides command, which overrides root:
workdir: "./root" // Default: ./root
cmds: [
{
name: "build"
workdir: "./command" // Override: ./command
implementations: [
{
script: "make"
workdir: "./implementation" // Final: ./implementation
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}
]
}
]
Monorepo Pattern
Perfect for monorepos with multiple packages:
cmds: [
{
name: "web build"
workdir: "./packages/web"
implementations: [{
script: "npm run build"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}]
},
{
name: "api build"
workdir: "./packages/api"
implementations: [{
script: "go build ./..."
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}]
},
{
name: "mobile build"
workdir: "./packages/mobile"
implementations: [{
script: "flutter build"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}]
}
]
Container Working Directory
For containers, the current directory is mounted to /workspace:
{
name: "build"
implementations: [{
script: """
pwd # /workspace
ls # Shows your project files
"""
runtimes: [{name: "container", image: "debian:bookworm-slim"}]
platforms: [{name: "linux"}]
}]
}
With workdir, that subdirectory becomes the container's working directory:
{
name: "build frontend"
workdir: "./frontend"
implementations: [{
script: """
pwd # /workspace/frontend
npm run build
"""
runtimes: [{name: "container", image: "node:20"}]
platforms: [{name: "linux"}]
}]
}
Cross-Platform Paths
Use forward slashes for cross-platform compatibility:
// Good - works everywhere
workdir: "./src/app"
// Avoid - Windows-specific
workdir: ".\\src\\app"
Invowk™ automatically converts to native path separators at runtime.
Real-World Examples
Frontend/Backend Split
cmds: [
{
name: "start frontend"
workdir: "./frontend"
implementations: [{
script: "npm run dev"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}]
},
{
name: "start backend"
workdir: "./backend"
implementations: [{
script: "go run ./cmd/server"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}]
}
]
Test Organization
cmds: [
{
name: "test unit"
workdir: "./tests/unit"
implementations: [{
script: "pytest"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}]
}]
},
{
name: "test integration"
workdir: "./tests/integration"
implementations: [{
script: "pytest"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}]
}]
},
{
name: "test e2e"
workdir: "./tests/e2e"
implementations: [{
script: "cypress run"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}]
}
]
Build in Subdirectory
{
name: "build"
workdir: "./src"
implementations: [{
script: """
# Now in ./src
go build -o ../bin/app ./...
"""
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}, {name: "windows"}]
}]
}
Best Practices
- Use relative paths: More portable across machines
- Forward slashes: Cross-platform compatible
- Root level for defaults: Override where needed
- Keep paths short: Easier to understand
Next Steps
- Interpreters - Use non-shell interpreters
- Platform-Specific - Per-platform implementations